[IMP] developer: rewrite the page on assets
closes odoo/documentation#1302
X-original-commit: 8c79319011
Signed-off-by: Géry Debongnie (ged) <ged@openerp.com>
This commit is contained in:
parent
3dd71a4817
commit
7b4879a06c
@ -9,18 +9,22 @@ Managing assets in Odoo is not as straightforward as it is in some other apps.
|
||||
One of the reasons is that we have a variety of situations where some, but not all
|
||||
of the assets are required. For example, the needs of the web client, the point of
|
||||
sale app, the website or even the mobile application are different. Also, some
|
||||
assets may be large, but are seldom needed. In that case, we sometimes want them
|
||||
to be loaded lazily.
|
||||
assets may be large, but are seldom needed: in that case we may want them
|
||||
to be :ref:`loaded lazily (on demand) <frontend/assets/lazy_loading>`.
|
||||
|
||||
The main idea is that we define a set of **bundles** in the module manifest. A
|
||||
bundle is here defined as a **list of file paths** (xml, javascript, css, scss).
|
||||
Files are declared using `glob <https://en.wikipedia.org/wiki/Glob_(programming)>`_ syntax, meaning that you can declare several asset
|
||||
files using a single line. Each matching file found will be appended to the
|
||||
`<head>` of the page, at most once, in the order the glob patterns are given.
|
||||
Bundles
|
||||
=======
|
||||
|
||||
As mentioned, the bundles are declared in each module's :file:`__manifest__.py`, under
|
||||
a dedicated `assets` key which contains a dictionary. The dictionary will map
|
||||
**bundles** (keys) to the list of **files** they contain (values). It looks like this:
|
||||
Odoo assets are grouped by *bundles*. Each bundle (a *list of file paths*
|
||||
of specific types: `xml`, `js`, `css` or `scss`) is listed in the
|
||||
:ref:`module manifest <reference/module/manifest>`. Files can be declared using
|
||||
`glob <https://en.wikipedia.org/wiki/Glob_(programming)>`_ syntax, meaning that
|
||||
you can declare several asset files using a single line.
|
||||
|
||||
The bundles are defined in each module's :file:`__manifest__.py`,
|
||||
with a dedicated `assets` key which contains a dictionary. The dictionary maps
|
||||
bundle names (keys) to the list of files they contain (values). It looks
|
||||
like this:
|
||||
|
||||
.. code-block:: py
|
||||
|
||||
@ -38,197 +42,217 @@ a dedicated `assets` key which contains a dictionary. The dictionary will map
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
The files in a bundle can then be inserted into a template by using the `t-call-assets`
|
||||
directive:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<t t-call-assets="web.assets_common" t-js="false"/>
|
||||
<t t-call-assets="web.assets_common" t-css="false"/>
|
||||
|
||||
Here is what happens when a template is rendered by the server with these directives:
|
||||
|
||||
- all the scss files described in the bundle are compiled into css files. A file
|
||||
named :file:`file.scss` will be compiled in a file named :file:`file.scss.css`.
|
||||
|
||||
- if we are in `debug=assets` mode
|
||||
|
||||
- the `t-call-assets` directive with the `t-js` attribute set to false will
|
||||
be replaced by a list of stylesheet tags pointing to the css files
|
||||
|
||||
- the `t-call-assets` directive with the `t-css` attribute set to false will
|
||||
link to the non minified bundle file (which uses sourcemaps)
|
||||
|
||||
- if we are not in `debug=assets` mode
|
||||
|
||||
- the css files will be concatenated and minified, then a stylesheet tag is
|
||||
generated
|
||||
|
||||
- the js files are concatenated and minified, then a script tag is generated
|
||||
|
||||
.. note::
|
||||
Assets files are cached, so in theory, a browser should only load them once.
|
||||
|
||||
Main bundles
|
||||
------------
|
||||
When the Odoo server is started, it checks the timestamp of each file in a bundle
|
||||
and, if necessary, create/recreate the corresponding bundles.
|
||||
|
||||
Here are some important bundles that most developers will need to know:
|
||||
Here is a list of some important bundles that most odoo developers will need to
|
||||
know:
|
||||
|
||||
- `web.assets_common`: this bundle contains most assets which are common to the
|
||||
web client, the website, and also the point of sale. This is supposed to contain
|
||||
web client, the website and also the point of sale. This is supposed to contain
|
||||
lower level building blocks for the odoo framework. Note that it contains the
|
||||
:file:`boot.js` file, which defines the odoo module system.
|
||||
|
||||
- `web.assets_backend`: this bundle contains the code specific to the web client
|
||||
(notably the web client/action manager/views) and all static XML templates used
|
||||
in the backend environment
|
||||
(notably the web client/action manager/views)
|
||||
|
||||
- `web.assets_frontend`: this bundle is about all that is specific to the public
|
||||
website: ecommerce, forum, blog, event management, ...
|
||||
website: ecommerce, portal, forum, blog, ...
|
||||
|
||||
- `web.assets_qweb`: all static XML templates used in the backend environment
|
||||
and in the point of sale.
|
||||
|
||||
- `web.qunit_suite_tests`: all javascript qunit testing code (tests, helpers, mocks)
|
||||
|
||||
- `web.qunit_mobile_suite_tests`: mobile specific qunit testing code
|
||||
|
||||
Asset types
|
||||
===========
|
||||
|
||||
There are three different asset types: code (`js` files), style (`css` or `scss`
|
||||
files) and templates (`xml` files).
|
||||
|
||||
Code
|
||||
Odoo supports :ref:`three different kinds of javascript files<frontend/js_modules>`.
|
||||
All these files are then processed (native JS modules are transformed into odoo
|
||||
modules), then minified (if not in `debug=assets` :ref:`mode <frontend/framework/assets_debug_mode>`)
|
||||
and concatenated. The result is then saved as a file attachment. These file
|
||||
attachments are usually loaded via a `<script>` tag in the `<head>` part of
|
||||
the page (as a static file).
|
||||
|
||||
Style
|
||||
Styling can be done with either `css` or `scss <https://sass-lang.com/>`_. Like
|
||||
the javascript files, these files are processed (`scss` files are converted into
|
||||
`css`), then minified (again, if not in `debug=assets` :ref:`mode <frontend/framework/assets_debug_mode>`)
|
||||
and concatenated. The result is then saved as a file attachment. They are
|
||||
then usually loaded via a `<link>` tag in the `<head>` part of the page (as
|
||||
a static file).
|
||||
|
||||
Template
|
||||
Templates (static `xml` files) are handled in a different way: they are simply
|
||||
read from the file system whenever they are needed, and concatenated.
|
||||
|
||||
Whenever the browser loads odoo, it calls the `/web/webclient/qweb/` controller
|
||||
to fetch the :ref:`templates <reference/qweb>`.
|
||||
|
||||
It is useful to know that in most cases, a browser only performs a request the
|
||||
first time it loads a page. This is because each of these assets are
|
||||
associated with a checksum, which is injected into the page source. The checksum
|
||||
is then added to the url, which means that it is possible to safely set the cache
|
||||
headers to a long period.
|
||||
|
||||
Operations on asset bundles
|
||||
---------------------------
|
||||
===========================
|
||||
|
||||
Typically, handling assets is quite trivial: you just need to add some new files
|
||||
to a frequently used bundle like 'common' or 'backend'. But there are other operations
|
||||
available to cover use cases bringing additional constraints. Such cases can mostly
|
||||
be covered with the following operations.
|
||||
Typically, handling assets is simple: you just need to add some new files
|
||||
to a frequently used bundle like `assets_common` or `assets_backend`. But there are other operations
|
||||
available to cover some more specific use cases.
|
||||
|
||||
- Add one or multiple file(s): `append`
|
||||
The proper way to add a file to a bundle in any addon is simple: it is just enough
|
||||
to add a glob pattern to the bundle in the file :file:`__manifest__.py` like so:
|
||||
Note that all directives targeting a certain asset file (i.e. `before`, `after`,
|
||||
`replace` and `remove`) need that file to be declared beforehand, either
|
||||
in manifests higher up in the hierarchy or in ``ir.asset`` records with a lower
|
||||
sequence.
|
||||
|
||||
.. code-block:: py
|
||||
`append`
|
||||
--------
|
||||
|
||||
'web.assets_common': [
|
||||
'my_addon/static/src/js/**/*',
|
||||
],
|
||||
This operation adds one or multiple file(s). Since it is the most common
|
||||
operation, it can be done by simply using the file name:
|
||||
|
||||
By default, adding a simple string to a bundle will append the files matching the
|
||||
glob pattern at the end of the bundle. Obviously, the pattern may also be directly
|
||||
a single file path.
|
||||
.. code-block:: python
|
||||
|
||||
- Add one or multiple file(s) at the beginning of the list: `prepend`
|
||||
Sometimes you need to put a certain file before the others in a bundle, when
|
||||
loading css file, for example. In this case, you can use the `prepend` directive
|
||||
by replacing the path with a pair `('prepend', <path>)`,
|
||||
like so:
|
||||
'web.assets_common': [
|
||||
'my_addon/static/src/js/**/*',
|
||||
],
|
||||
|
||||
.. code-block:: py
|
||||
By default, adding a simple string to a bundle will append the files matching the
|
||||
glob pattern at the end of the bundle. Obviously, the pattern may also be directly
|
||||
a single file path.
|
||||
|
||||
'web.assets_common': [
|
||||
('prepend', 'my_addon/static/src/css/bootstrap_overridden.scss'),
|
||||
],
|
||||
`prepend`
|
||||
---------
|
||||
|
||||
- Add one or multiple file(s) before a specific file: `before`
|
||||
Prepending a file at the beginning of a bundle might not be precise enough. The
|
||||
`before` directive can be used to add the given file(s) right *before* the target
|
||||
file. It is declared by replacing the normal path with a 3-element tuple
|
||||
`('before', <target>, <path>)`, like so:
|
||||
Add one or multiple file(s) at the beginning of the bundle.
|
||||
|
||||
.. code-block:: py
|
||||
Useful when you need to put a certain file before the others in a bundle (for
|
||||
example with css files). The `prepend` operation is invoked with the following
|
||||
syntax: `('prepend', <path>)`.
|
||||
|
||||
'web.assets_common': [
|
||||
('before', 'web/static/src/css/bootstrap_overridden.scss', 'my_addon/static/src/css/bootstrap_overridden.scss'),
|
||||
],
|
||||
.. code-block:: python
|
||||
|
||||
- Add one or multiple file(s) after a specific file: `after`
|
||||
Same as `before`, with the matching file(s) appended right *after* the target file.
|
||||
It is declared by replacing the normal path with a 3-element tuple
|
||||
`('after', <target>, <path>)`, like so:
|
||||
'web.assets_common': [
|
||||
('prepend', 'my_addon/static/src/css/bootstrap_overridden.scss'),
|
||||
],
|
||||
|
||||
.. code-block:: py
|
||||
`before`
|
||||
--------
|
||||
|
||||
'web.assets_common': [
|
||||
('after', 'web/static/src/css/list_view.scss', 'my_addon/static/src/css/list_view.scss'),
|
||||
],
|
||||
Add one or multiple file(s) before a specific file.
|
||||
|
||||
- Use nested bundles: `include`
|
||||
The `include` directive is a way to use a same bundle in other bundles to minimize
|
||||
the size of your manifest. In Odoo we use sub bundles (prefixed with an underscore
|
||||
by convention) to batch files used in multiple other bundles. You can then
|
||||
specify the sub bundle as a pair `('include', <bundle>)` like this:
|
||||
Prepending a file at the beginning of a bundle might not be precise enough. The
|
||||
`before` directive can be used to add the given file(s) right *before* the target
|
||||
file. It is declared by replacing the normal path with a 3-element tuple
|
||||
`('before', <target>, <path>)`.
|
||||
|
||||
.. code-block:: py
|
||||
.. code-block:: python
|
||||
|
||||
'web.assets_common': [
|
||||
('include', 'web._primary_variables'),
|
||||
],
|
||||
'web.assets_common': [
|
||||
('before', 'web/static/src/css/bootstrap_overridden.scss', 'my_addon/static/src/css/bootstrap_overridden.scss'),
|
||||
],
|
||||
|
||||
- Remove one or multiple file(s): `remove`
|
||||
In some additional module you may want to get rid of the call of a certain asset
|
||||
in a bundle. Any file can be removed from an existing bundle using the `remove`
|
||||
directive by specifying a pair `('remove', <target>)`:
|
||||
`after`
|
||||
-------
|
||||
|
||||
.. code-block:: py
|
||||
Add one or multiple file(s) after a specific file.
|
||||
|
||||
'web.assets_common': [
|
||||
('remove', 'web/static/src/js/boot.js'),
|
||||
],
|
||||
Same as `before`, with the matching file(s) appended right *after* the target file.
|
||||
It is declared by replacing the normal path with a 3-element tuple
|
||||
`('after', <target>, <path>)`.
|
||||
|
||||
- Replace an asset file with one or multiple file(s): `replace`
|
||||
Let us now say that an asset need not only to be removed, but you also want to insert
|
||||
your new version of that asset at the same exact position. This can be done with
|
||||
the `replace` directive, using a 3-element tuple `('replace', <target>, <path>)`:
|
||||
.. code-block:: python
|
||||
|
||||
.. code-block:: py
|
||||
'web.assets_common': [
|
||||
('after', 'web/static/src/css/list_view.scss', 'my_addon/static/src/css/list_view.scss'),
|
||||
],
|
||||
|
||||
'web.assets_common': [
|
||||
('replace', 'web/static/src/js/boot.js', 'my_addon/static/src/js/boot.js'),
|
||||
],
|
||||
`include`
|
||||
---------
|
||||
|
||||
Note that all directives targeting a certain asset file (i.e. `before`, `after`,
|
||||
`replace` and `remove`) need that file to be declared beforehand, either
|
||||
in manifests higher up in the hierarchy or in ``ir.asset`` records with a lower
|
||||
sequence.
|
||||
Use nested bundles.
|
||||
|
||||
.. note::
|
||||
The `include` directive is a way to use a bundle in other bundles to minimize
|
||||
the size of your manifest. In Odoo we use sub bundles (prefixed with an underscore
|
||||
by convention) to batch files used in multiple other bundles. You can then
|
||||
specify the sub bundle as a pair `('include', <bundle>)` like this:
|
||||
|
||||
Note that the files in a bundle are all loaded immediately when the user loads the
|
||||
odoo web client. This means that the files are transferred through the network
|
||||
every time (except when the browser cache is active). In some cases, it may be
|
||||
better to lazyload some assets. For example, if a widget requires a large
|
||||
library, and that widget is not a core part of the experience, then it may be
|
||||
a good idea to only load the library when the widget is actually created. The
|
||||
widget class has actually built-in support just for this use case. (see section
|
||||
:ref:`reference/javascript_reference/qweb`)
|
||||
.. code-block:: python
|
||||
|
||||
Assets loading order
|
||||
--------------------
|
||||
'web.assets_common': [
|
||||
('include', 'web._primary_variables'),
|
||||
],
|
||||
|
||||
`remove`
|
||||
--------
|
||||
|
||||
Remove one or multiple file(s).
|
||||
|
||||
In some cases, you may want to remove one or multiple files from a bundle. This
|
||||
can be done using the `remove` directive by specifying a pair
|
||||
`('remove', <target>)`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
'web.assets_common': [
|
||||
('remove', 'web/static/src/js/boot.js'),
|
||||
],
|
||||
|
||||
`replace`
|
||||
---------
|
||||
|
||||
Replace an asset file with one or multiple file(s).
|
||||
|
||||
Let us say that an asset needs not only to be removed, but you also want to insert
|
||||
your new version of that asset at the same exact position. This can be done with
|
||||
the `replace` directive, using a 3-element tuple `('replace', <target>, <path>)`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
'web.assets_common': [
|
||||
('replace', 'web/static/src/js/boot.js', 'my_addon/static/src/js/boot.js'),
|
||||
],
|
||||
|
||||
|
||||
Loading order
|
||||
=============
|
||||
|
||||
The order in which assets are loaded is sometimes critical and must be deterministic,
|
||||
mostly for stylesheets priorities and setup scripts. Assets in Odoo are processed
|
||||
as follows.
|
||||
as follows:
|
||||
|
||||
1. When an asset bundle is called (e.g. `t-call-assets="web.assets_common"`), an empty
|
||||
list of assets is generated
|
||||
#. When an asset bundle is called (e.g. `t-call-assets="web.assets_common"`), an empty
|
||||
list of assets is generated
|
||||
|
||||
2. All records of type ``ir.asset`` matching the bundle will be fetched and sorted
|
||||
by sequence number. Then all records with a sequence strictly less than 16 will
|
||||
be processed and applied to the current list of assets.
|
||||
#. All records of type `ir.asset` matching the bundle are fetched and sorted
|
||||
by sequence number. Then all records with a sequence strictly less than 16 are
|
||||
processed and applied to the current list of assets.
|
||||
|
||||
3. All modules declaring assets for said bundle in their manifest will apply their
|
||||
assets operations to this list. This is done following the order of modules dependencies
|
||||
(e.g. 'web' assets will be processed before 'website'). If a directive tries to add
|
||||
a file already present in the list, nothing is done for that file. In other word,
|
||||
only the first occurrence of a file is kept in the list.
|
||||
#. All modules declaring assets for said bundle in their manifest apply their
|
||||
assets operations to this list. This is done following the order of modules dependencies
|
||||
(e.g. `web` assets is processed before 'website'). If a directive tries to add
|
||||
a file already present in the list, nothing is done for that file. In other word,
|
||||
only the first occurrence of a file is kept in the list.
|
||||
|
||||
4. The remaining ``ir.asset`` records (those with a sequence greater than or equal
|
||||
to 16) are then processed and applied as well.
|
||||
#. The remaining `ir.asset` records (those with a sequence greater than or equal
|
||||
to 16) are then processed and applied as well.
|
||||
|
||||
Assets declared in the manifest may need to be loaded in a particular order, for
|
||||
example :file:`jquery.js` must be loaded before all other jquery scripts when loading the
|
||||
lib folder. One solution would be to create an ``ir.asset`` record with a lower sequence
|
||||
or a 'prepend' directive, but there is another simpler way to do so.
|
||||
lib folder. One solution would be to create an :ref:`ir.asset <frontend/assets/ir_asset>`
|
||||
record with a lower sequence or a 'prepend' directive, but there is another simpler
|
||||
way to do so.
|
||||
|
||||
Since the unicity of each file path in the list of assets is guaranteed, you can
|
||||
mention any specific file before a glob that includes it. That file will thus appear
|
||||
in the list before all the others included in the glob.
|
||||
|
||||
.. code-block:: py
|
||||
.. code-block:: python
|
||||
|
||||
'web.assets_common': [
|
||||
'my_addon/static/lib/jquery/jquery.js',
|
||||
@ -241,13 +265,62 @@ in the list before all the others included in the glob.
|
||||
to depend on it. Trying to operate on assets that have yet to be declared will
|
||||
result in an error.
|
||||
|
||||
.. _frontend/assets/lazy_loading:
|
||||
|
||||
Lazy loading assets
|
||||
===================
|
||||
|
||||
It is sometimes useful to load files and/or asset bundles dynamically, for
|
||||
example to only load a library once it is needed. To do that, the Odoo framework
|
||||
provides a few helper functions, located in :file:`@web/core/assets`.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
await loadAssets({
|
||||
jsLibs: ["/web/static/lib/stacktracejs/stacktrace.js"],
|
||||
});
|
||||
|
||||
|
||||
.. js:function:: loadAssets(assets)
|
||||
|
||||
:param Object assets: a description of various assets that should be loaded
|
||||
:returns: Promise<void>
|
||||
|
||||
Load the assets described py the `assets` parameter. It is an object that
|
||||
may contain the following keys:
|
||||
|
||||
.. list-table::
|
||||
:widths: 20 20 60
|
||||
:header-rows: 1
|
||||
|
||||
* - Key
|
||||
- Type
|
||||
- Description
|
||||
* - `jsLibs`
|
||||
- `string[]`
|
||||
- a list of urls of javascript files
|
||||
* - `cssLibs`
|
||||
- `string[]`
|
||||
- a list of urls of css files
|
||||
|
||||
|
||||
.. js:function:: useAssets(assets)
|
||||
|
||||
:param Object assets: a description of various assets that should be loaded
|
||||
|
||||
This hook is useful when components need to load some assets in their
|
||||
`onWillStart` method. It internally calls `loadAssets`.
|
||||
|
||||
.. _frontend/assets/ir_asset:
|
||||
|
||||
The asset model (`ir.asset`)
|
||||
------------------------------
|
||||
============================
|
||||
|
||||
In most cases the assets declared in the manifest will largely suffice. Yet for
|
||||
more flexibility, the framework also supports dynamic assets declared in the
|
||||
database.
|
||||
This is done by creating ``ir.asset`` records. Those will be processed as if they
|
||||
|
||||
This is done by creating `ir.asset` records. Those will be processed as if they
|
||||
were found in a module manifest, and they give the same expressive power as their
|
||||
manifest counterparts.
|
||||
|
||||
|
@ -20,6 +20,8 @@ documents the list of hooks provided by the Odoo web framework.
|
||||
|
||||
* - Name
|
||||
- Short Description
|
||||
* - :ref:`useAssets <frontend/hooks/useassets>`
|
||||
- load assets
|
||||
* - :ref:`useBus <frontend/hooks/usebus>`
|
||||
- subscribe and unsubscribe to a bus
|
||||
* - :ref:`usePager <frontend/hooks/usepager>`
|
||||
@ -27,6 +29,22 @@ documents the list of hooks provided by the Odoo web framework.
|
||||
* - :ref:`usePosition <frontend/hooks/useposition>`
|
||||
- position an element relative to a target
|
||||
|
||||
.. _frontend/hooks/useassets:
|
||||
|
||||
useAssets
|
||||
=========
|
||||
|
||||
Location
|
||||
--------
|
||||
|
||||
`@web/core/assets`
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
See the section on :ref:`lazy loading assets <frontend/assets/lazy_loading>` for
|
||||
more details.
|
||||
|
||||
.. _frontend/hooks/usebus:
|
||||
|
||||
useBus
|
||||
|
@ -1,3 +1,5 @@
|
||||
.. _frontend/js_modules:
|
||||
|
||||
==================
|
||||
Javascript Modules
|
||||
==================
|
||||
|
Loading…
Reference in New Issue
Block a user