Javascript modulok

Az Odoo három különböző típusú javascript fájlt támogat:

Ahogy a eszközkezelési oldalon le van írva, az összes javascript fájl össze van csomagolva és a böngészőnek van kiszolgálva. Vegye figyelembe, hogy a natív javascript fájlokat az Odoo szerver dolgozza fel és Odoo egyedi modulokká alakítja át.

Röviden magyarázzuk el az egyes javascript fájltípusok mögötti célt. Az egyszerű javascript fájlokat csak külső könyvtárakhoz és néhány kis, specifikus alacsony szintű célra kell fenntartani. Minden új javascript fájlt a natív javascript modulrendszerben kell létrehozni. Az egyedi modulrendszer csak a régi, még nem konvertált fájlok esetében hasznos.

Egyszerű Javascript fájlok

Az egyszerű javascript fájlok tetszőleges tartalmat tartalmazhatnak. Javasolt az iife azonnal meghívott függvény végrehajtás stílus használata ilyen fájl írásakor:

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

Az ilyen fájlok előnye, hogy elkerüljük a lokális változók kiszivárgását a globális térbe.

Nyilvánvaló, hogy az egyszerű javascript fájlok nem kínálják a modulrendszer előnyeit, ezért óvatosnak kell lenni a csomagban lévő sorrenddel (mivel a böngésző pontosan ebben a sorrendben fogja végrehajtani őket).

Megjegyzés

Az Odoo-ban minden külső könyvtár egyszerű javascript fájlként van betöltve.

Natív Javascript Modulok

Odoo javascript code uses the native javascript module system. This is simpler, and brings the benefits of a better developer experience with a better integration with the IDE.

Let us consider the following module, located in web/static/src/file_a.js:

import { someFunction } from "./file_b";

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

There is a very important point to know: by default Odoo transpiles files under /static/src and /static/tests into Odoo modules. This file will then be transpiled into an Odoo module that looks like this:

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

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

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

return __exports;
)};

So, as you can see, the transformation is basically adding odoo.define on top and updating the import/export statements. This is an opt-out system, it’s possible to tell the transpiler to ignore the file.

/** @odoo-module ignore **/
(function () {
  const sum = (a, b) => a + b;
  console.log(sum(1, 2));
)();

Note the comment in the first line: it describes that this file should be ignored.

In other folders, files aren’t transpiled by default, it is opt-in. Odoo will look at the first line of a JS file and check if it contains a comment with @odoo-module and without the tag ignore. If so, it will automatically be converted to an Odoo module.

/** @odoo-module **/
export function sum(a, b) {
  return a + b;
}

Another important point is that the transpiled module has an official name: @web/file_a. This is the actual name of the module. Every relative imports will be converted as well. Every file located in an Odoo addon some_addon/static/src/path/to/file.js will be assigned a name prefixed by the addon name like this: @some_addon/path/to/file.

A relatív importok működnek, de csak akkor, ha a modulok ugyanabban az Odoo kiegészítőben vannak. Tehát képzeljük el, hogy a következő fájlstruktúrával rendelkezünk:

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

A file_b fájl importálhatja a file_a fájlt így:

import {something} from `./file_a`;

De a file_c fájlnak a teljes nevet kell használnia:

import {something} from `@web/file_a`;

Aliasolt modulok

Mivel az Odoo modulok eltérő modul elnevezési mintát követnek, létezik egy rendszer, amely lehetővé teszi a zökkenőmentes átmenetet az új rendszer felé. Jelenleg, ha egy fájl modullá van konvertálva (és így követi az új elnevezési konvenciót), a projektben lévő más fájlok, amelyek még nem lettek ES6-szerű szintaxisra konvertálva, nem tudják igényelni a modult. Az aliasok itt vannak, hogy a régi neveket újakkal térképezzék fel egy kis proxy funkció létrehozásával. A modult ezután új és régi nevén is lehet hívni.

Ilyen alias hozzáadásához a fájl tetején található megjegyzés címkének így kell kinéznie:

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

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

Ezután a lefordított modul létrehoz egy alias-t a kért névvel:

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

The default behaviour of aliases is to re-export the default value of the module they alias. This is because „classic” modules generally export a single value which would be used directly, roughly matching the semantics of default exports. However it is also possible to delegate more directly, and follow the exact behaviour of the aliased module:

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

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

Ebben az esetben ez egy alias-t definiál pontosan az eredeti modul által exportált értékekkel:

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

Megjegyzés

Csak egy alias definiálható ezzel a módszerrel. Ha szüksége lenne egy másikra, hogy például három névvel hívhassa ugyanazt a modult, manuálisan kellene hozzáadnia egy proxy-t. Ez nem jó gyakorlat, és kerülendő, hacsak nincs más lehetőség.

Korlátozások

Teljesítmény okokból az Odoo nem használ teljes javascript elemzőt a natív modulok átalakítására. Ezért számos korlátozás van, beleértve, de nem kizárólagosan:

  • egy import vagy export kulcsszó előtt nem állhat nem szóköz karakter,

  • egy több soros megjegyzés vagy szöveg nem tartalmazhat olyan sort, amely import vagy export-tal kezdődik

    // 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 ...
    */
    
  • amikor egy objektumot exportál, nem tartalmazhat megjegyzést

    // 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"
    
  • Az Odoo-nak szüksége van egy módszerre annak meghatározására, hogy egy modult egy útvonal (mint ./views/form_view) vagy egy név (mint web.FormView) ír le. Ehhez egy heurisztikát kell használnia: ha van egy / a névben, azt útvonalnak tekinti. Ez azt jelenti, hogy az Odoo már nem támogatja igazán a /-t tartalmazó modulneveket.

As „classic” modules are not deprecated and there is currently no plan to remove them, you can and should keep using them if you encounter issues with, or are constrained by the limitations of, native modules. Both styles can coexist within the same Odoo addon.

Odoo Modul Rendszer

Az Odoo egy kis modulrendszert definiált (a addons/web/static/src/js/boot.js fájlban található, amelyet először be kell tölteni). Az Odoo modulrendszere, amelyet az AMD inspirált, azzal működik, hogy a define függvényt definiálja a globális odoo objektumon. Ezután minden javascript modult úgy definiálunk, hogy meghívjuk ezt a függvényt. Az Odoo keretrendszerben egy modul egy kódrészlet, amelyet a lehető leghamarabb végrehajtanak. Van egy neve és esetleg néhány függősége. Amikor a függőségei betöltődnek, a modul is betöltődik. A modul értéke ekkor a modult definiáló függvény visszatérési értéke.

Például így nézhet ki:

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

    var A = ...;

    return A;
});

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

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

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

    return B;
});

Ha néhány függőség hiányzik/nem áll készen, akkor a modul egyszerűen nem töltődik be. Néhány másodperc múlva figyelmeztetés jelenik meg a konzolon.

Vegye figyelembe, hogy a körkörös függőségek nem támogatottak. Ez logikus, de azt jelenti, hogy óvatosnak kell lenni.

Egy modul definiálása

Az odoo.define metódus három argumentumot kap:

  • moduleName: a javascript modul neve. Egyedi karakterláncnak kell lennie. A konvenció az, hogy az odoo addon neve után egy specifikus leírás következik. Például a web.Widget egy modult ír le, amely a web addonban van definiálva, és egy Widget osztályt exportál (mivel az első betű nagybetűs)

    Ha a név nem egyedi, kivétel keletkezik, amely megjelenik a konzolon.

  • dependencies: It should be a list of strings, each corresponding to a javascript module. This describes the dependencies that are required to be loaded before the module is executed.

  • finally, the last argument is a function which defines the module. Its return value is the value of the module, which may be passed to other modules requiring it.

    odoo.define('module.Something', ['web.ajax'], function (require) {
        "use strict";
    
        var ajax = require('web.ajax');
    
        // some code here
        return something;
    });
    

Ha hiba történik, az naplózásra kerül (hibakeresési módban) a konzolon:

  • Hiányzó függőségek: Ezek a modulok nem jelennek meg az oldalon. Lehetséges, hogy a JavaScript fájl nincs az oldalon, vagy a modul neve helytelen

  • Sikertelen modulok: JavaScript hiba észlelve

  • Elutasított modulok: A modul elutasított Promise-t ad vissza. Ez (és a tőle függő modulok) nem töltődik be.

  • Elutasított kapcsolt modulok: Modulok, amelyek egy elutasított modultól függenek

  • Nem betöltött modulok: Modulok, amelyek egy hiányzó vagy sikertelen modultól függenek