Mô-đun Javascript

SoOn hỗ trợ ba loại tệp javascript khác nhau:

Như được mô tả trong trang quản lý tài sản, tất cả các tệp javascript được nhóm lại với nhau và cung cấp cho trình duyệt. Lưu ý rằng các tệp javascript gốc được máy chủ SoOn xử lý và chuyển đổi thành các mô-đun tùy chỉnh của SoOn.

Hãy để chúng tôi giải thích ngắn gọn mục đích đằng sau từng loại tệp javascript. Các tệp javascript đơn giản chỉ nên được dành riêng cho các thư viện bên ngoài và một số mục đích cấp thấp cụ thể nhỏ. Tất cả các tệp javascript mới phải được tạo trong hệ thống mô-đun javascript gốc. Hệ thống mô-đun tùy chỉnh chỉ hữu ích cho các tệp cũ, chưa được chuyển đổi.

Tệp Javascript đơn giản

Các tệp javascript đơn giản có thể chứa nội dung tùy ý. Bạn nên sử dụng kiểu iife thực thi hàm được gọi ngay lập tức khi ghi một tệp như vậy:

(function () {
  // some code here
  let a = 1;
  console.log(a);
})();

Ưu điểm của các tệp như vậy là chúng tôi tránh rò rỉ các biến cục bộ ra phạm vi toàn cầu.

Rõ ràng, các tệp javascript đơn giản không mang lại lợi ích của hệ thống mô-đun, vì vậy người ta cần phải cẩn thận về thứ tự trong gói (vì trình duyệt sẽ thực thi chúng chính xác theo thứ tự đó).

Ghi chú

Trong SoOn, tất cả thư viện bên ngoài được tải dưới dạng tệp javascript đơn giản.

Mô-đun Javascript gốc

Hầu hết mã javascript SoOn mới nên sử dụng hệ thống mô-đun javascript gốc. Điều này đơn giản hơn và mang lại lợi ích về trải nghiệm tốt hơn cho nhà phát triển với khả năng tích hợp tốt hơn với IDE.

Có một điểm rất quan trọng cần biết: SoOn cần biết tệp nào nên được dịch sang SoOn module và tệp nào không nên dịch. Đây là một hệ thống chọn tham gia: SoOn sẽ xem dòng đầu tiên của tệp JS và kiểm tra xem nó có chứa chuỗi @odoo-module hay không. Nếu vậy, nó sẽ tự động được chuyển đổi thành mô-đun SoOn.

Ví dụ: chúng ta hãy xem xét mô-đun sau, nằm trong web/static/src/file_a.js:

/** @odoo-module **/
import { someFunction } from './file_b';

export function otherFunction(val) {
    return someFunction(val + 3);
}

Hãy lưu ý nhận xét ở dòng đầu tiên: nó mô tả rằng tập tin này cần được chuyển đổi. Bất kỳ tệp nào không có nhận xét này sẽ được giữ nguyên (rất có thể sẽ có lỗi). Sau đó, tệp này sẽ được dịch sang mô-đun SoOn trông như thế này:

odoo.define('@web/file_a', function (require) {
'use strict';
let __exports = {};

const { someFunction } = require("@web/file_b");

__exports.otherFunction = function otherFunction(val) {
    return someFunction(val + 3);
};

return __exports;
)};

Vì vậy, như bạn có thể thấy, việc chuyển đổi về cơ bản là thêm odoo.define lên trên và cập nhật các câu lệnh nhập/xuất.

Một điểm quan trọng khác là mô-đun đã dịch có tên chính thức: @web/file_a. Đây là tên thực tế của mô-đun. Mọi hàng nhập khẩu tương đối cũng sẽ được chuyển đổi. Mọi tệp nằm trong một addon của SoOn some_addon/static/src/path/to/file.js sẽ được gán một tên có tiền tố là tên addon như thế này: @some_addon/path/to/file.

Việc nhập tương đối có hiệu quả nhưng chỉ khi các mô-đun nằm trong cùng một phần bổ trợ của SoOn. Vì vậy, hãy tưởng tượng rằng chúng ta có cấu trúc tệp sau:

addons/
    web/
        static/
            src/
                file_a.js
                file_b.js
    stock/
        static/
            src/
                file_c.js

Tệp file_b có thể nhập file_a như thế này:

/** @odoo-module **/
import {something} from `./file_a`

Nhưng file_c cần sử dụng tên đầy đủ:

/** @odoo-module **/
import {something} from `@web/file_a`

Mô-đun bí danh

Bởi vì Các mô-đun SoOn tuân theo một mẫu đặt tên mô-đun khác, nên một hệ thống tồn tại để cho phép chuyển đổi suôn sẻ sang hệ thống mới. Hiện tại, nếu một tệp được chuyển đổi thành mô-đun (và do đó tuân theo quy ước đặt tên mới), các tệp khác chưa được chuyển đổi sang cú pháp giống ES6 trong dự án sẽ không thể yêu cầu mô-đun. Các bí danh ở đây để ánh xạ tên cũ với tên mới bằng cách tạo một hàm proxy nhỏ. Sau đó, mô-đun có thể được gọi bằng tên cũ * và * mới của nó.

Để thêm bí danh như vậy, thẻ nhận xét ở đầu tệp sẽ trông như thế này:

/** @odoo-module alias=web.someName**/
import { someFunction } from './file_b';

export default function otherFunction(val) {
    return someFunction(val + 3);
}

Sau đó, mô-đun đã dịch cũng sẽ tạo bí danh với tên được yêu cầu:

odoo.define(`web.someName`, function(require) {
    return require('@web/file_a')[Symbol.for("default")];
});

Hành vi mặc định của bí danh là xuất lại giá trị mặc định của mô-đun mà chúng đặt bí danh. Điều này là do các mô-đun "cổ điển" thường xuất một giá trị duy nhất sẽ được sử dụng trực tiếp, gần giống với ngữ nghĩa của việc xuất mặc định. Tuy nhiên, cũng có thể ủy quyền trực tiếp hơn và thực hiện theo hành vi chính xác của mô-đun bí danh:

/** @odoo-module alias=web.someName default=0**/
import { someFunction } from './file_b';

export function otherFunction(val) {
    return someFunction(val + 3);
}

Trong trường hợp đó, điều này sẽ xác định một bí danh với chính xác các giá trị được mô-đun gốc xuất ra:

odoo.define(`web.someName`, function(require) {
    return require('@web/file_a');
});

Ghi chú

Chỉ có thể xác định một bí danh bằng phương pháp này. Nếu bạn cần một tên khác, chẳng hạn như ba tên để gọi cùng một mô-đun, bạn sẽ phải thêm proxy theo cách thủ công. Đây không phải là cách làm tốt và nên tránh trừ khi không còn lựa chọn nào khác.

Hạn chế

Vì lý do hiệu suất, SoOn không sử dụng trình phân tích cú pháp javascript đầy đủ để chuyển đổi các mô-đun gốc. Do đó, có một số hạn chế bao gồm nhưng không giới hạn ở:

  • từ khóa import hoặc export không thể được đặt trước ký tự không phải khoảng trắng,

  • một nhận xét hoặc chuỗi nhiều dòng không được có dòng bắt đầu bằng import hoặc export

    // supported
    import X from "xxx";
    export X;
      export default X;
        import X from "xxx";
    
    /*
     * import X ...
     */
    
    /*
     * export X
     */
    
    
    // not supported
    
    var a= 1;import X from "xxx";
    /*
      import X ...
    */
    
  • khi bạn xuất một đối tượng, nó không thể chứa nhận xét

    // supported
    export {
      a as b,
      c,
      d,
    }
    
    export {
      a
    } from "./file_a"
    
    
    // not supported
    export {
      a as b, // this is a comment
      c,
      d,
    }
    
    export {
      a /* this is a comment */
    } from "./file_a"
    
  • SoOn cần một cách để xác định xem một mô-đun có được mô tả bằng một đường dẫn (như ./views/form_view) hay một tên (như web.FormView). Nó phải sử dụng phương pháp phỏng đoán để làm việc đó: nếu có / trong tên, nó được coi là một đường dẫn. Điều này có nghĩa là SoOn không thực sự hỗ trợ tên mô-đun có / nữa.

Vì các mô-đun "cổ điển" không được dùng nữa và hiện không có kế hoạch loại bỏ chúng nên bạn có thể và nên tiếp tục sử dụng chúng nếu gặp phải sự cố hoặc bị hạn chế bởi các hạn chế của mô-đun gốc. Cả hai phong cách có thể cùng tồn tại trong cùng một tiện ích bổ sung SoOn.

Hệ thống mô-đun SoOn

SoOn đã xác định một hệ thống mô-đun nhỏ (nằm trong tệp addons/web/static/src/js/boot.js, tệp này cần được tải trước). Hệ thống mô-đun SoOn, lấy cảm hứng từ AMD, hoạt động bằng cách xác định hàm define trên đối tượng odoo toàn cầu. Sau đó, chúng tôi xác định từng mô-đun javascript bằng cách gọi hàm đó. Trong khung SoOn, mô-đun là một đoạn mã sẽ được thực thi sớm nhất có thể. Nó có tên và có thể có một số phụ thuộc. Khi các phần phụ thuộc của nó được tải, một mô-đun cũng sẽ được tải. Giá trị của mô-đun khi đó là giá trị trả về của hàm xác định mô-đun.

Ví dụ, nó có thể trông như thế này:

// in file a.js
odoo.define('module.A', function (require) {
    "use strict";

    var A = ...;

    return A;
});

// in file b.js
odoo.define('module.B', function (require) {
    "use strict";

    var A = require('module.A');

    var B = ...; // something that involves A

    return B;
});

Một cách khác để xác định một mô-đun là đưa ra một danh sách rõ ràng các phần phụ thuộc trong đối số thứ hai.

odoo.define('module.Something', ['module.A', 'module.B'], function (require) {
    "use strict";

    var A = require('module.A');
    var B = require('module.B');

    // some code
});

Nếu một số phần phụ thuộc bị thiếu/chưa sẵn sàng thì mô-đun sẽ không được tải. Sẽ có cảnh báo trong bảng điều khiển sau vài giây.

Lưu ý rằng phụ thuộc vòng tròn không được hỗ trợ. Nó có ý nghĩa, nhưng nó có nghĩa là người ta cần phải cẩn thận.

Xác định một mô-đun

Phương thức odoo.define được đưa ra ba đối số:

  • moduleName: tên của mô-đun javascript. Nó phải là một chuỗi duy nhất. Quy ước là có tên của addon odoo theo sau là một mô tả cụ thể. Ví dụ: web.Widget mô tả một mô-đun được xác định trong addon web, xuất một lớp Widget (vì chữ cái đầu tiên được viết hoa)

    Nếu tên không phải là duy nhất, một ngoại lệ sẽ được đưa ra và hiển thị trong bảng điều khiển.

  • phụ thuộc: đối số thứ hai là tùy chọn. Nếu được cung cấp, nó phải là danh sách các chuỗi, mỗi chuỗi tương ứng với một mô-đun javascript. Phần này mô tả các phần phụ thuộc cần được tải trước khi mô-đun được thực thi. Nếu các phần phụ thuộc không được đưa ra rõ ràng ở đây thì hệ thống mô-đun sẽ trích xuất chúng khỏi hàm bằng cách gọi toString trên đó, sau đó sử dụng biểu thức chính quy để tìm tất cả các câu lệnh require.

    odoo.define('module.Something', ['web.ajax'], function (require) {
        "use strict";
    
        var ajax = require('web.ajax');
    
        // some code here
        return something;
    });
    
  • cuối cùng, đối số cuối cùng là hàm xác định mô-đun. Giá trị trả về của nó là giá trị của mô-đun, có thể được chuyển đến các mô-đun khác yêu cầu nó. Lưu ý rằng có một ngoại lệ nhỏ đối với các mô-đun không đồng bộ, hãy xem phần tiếp theo.

Nếu xảy ra lỗi, nó sẽ được ghi lại (ở chế độ gỡ lỗi) trong bảng điều khiển:

  • Thiếu phần phụ thuộc: Các mô-đun này không xuất hiện trên trang. Có thể tệp JavaScript không có trong trang hoặc tên mô-đun sai

  • Mô-đun bị lỗi: Đã phát hiện thấy lỗi javascript

  • Mô-đun bị từ chối: Mô-đun trả về Lời hứa bị từ chối. Nó (và các mô-đun phụ thuộc của nó) không được tải.

  • Mô-đun liên kết bị từ chối: Các mô-đun phụ thuộc vào mô-đun bị từ chối

  • Mô-đun không được tải: Các mô-đun phụ thuộc vào mô-đun bị thiếu hoặc bị lỗi

Mô-đun không đồng bộ

Có thể xảy ra trường hợp một mô-đun cần thực hiện một số công việc trước khi nó sẵn sàng. Ví dụ: nó có thể thực hiện rpc để tải một số dữ liệu. Trong trường hợp đó, mô-đun có thể chỉ cần trả lại một lời hứa. Hệ thống mô-đun sẽ chỉ đợi lời hứa hoàn thành trước khi đăng ký mô-đun.

odoo.define('module.Something', function (require) {
    "use strict";

    var ajax = require('web.ajax');

    return ajax.rpc(...).then(function (result) {
        // some code here
        return something;
    });
});