-
Notifications
You must be signed in to change notification settings - Fork 86
ES6 modules migration
Previous architecture / shortcomings
- a unique "one-ring to rule them all"
ngeo
Angular module (+ one for gmf) -
src/ngeo.js
/contribs/gmf/src/gmf.js
is a holdall (namespace, root Angular module, ...) - each Angular piece of code does
goog.require('ngeo')
and registers itself into the "one-ring" module - a ton of "ignore unused require" annotations
New modular architecture
- the ngeo namespace stays in
src/ngeo.js
(with content like ngeo.baseTemplateUrl = 'ngeo';) - the ngeo one-ring Angular module moves to
src/module.js
and is renamed"ngeo.module"
(this is the module currently required from all files and where we currently register angular components, directives, services, values). This is only transitory, it will be removed at the end of the migration. - the dist entrypoint is created in
src/distmodule.js
and is named"ngeo.distmodule"
it requires all top level Angular modules and extras and adds them to its dependencies. It is used to generatedist/ngeo.js
containing the entire library - each Angular file is wrapped in a dedicated Angular module which is stored in
exports
for goog.module or the symbol for goog.provide example for a component:goog.module('ngeo.mycomponent')
...exports = angular.module('ngeo.mycomponent', dependencies).component('ngeo.mycomponent', descr)
orgoog.provide('ngeo.mycomponent')
...ngeo.mycomponent = angular.module('ngeo.mycomponent', dependencies).component('ngeo.mycomponent', descr)
if the component requires some other service / partial, it should require them and add their Angular modules as dependencies (use [] if no dependency). It is the same for external Angular module dependencies: ng-touch, .... the created angular module is added as dependency to the "one-ring" module (with ngeo.module.requires.push(theModule.name)) - Angular files are grouped in Angular "top level" modules Example: the search top level module goog.requires the searchdirective (module) and adds it as dependency How to split the library in consistent toplevel modules is to be discussed with someone like Stéphane and Alexandre
- partials, services, ... are moved to the directory of their top level Angular module, there are no more "partials" or "services" directories. General purpose services can be added to the "src/utils" top level module.
- Very specific Angular files are not added to the top level modules; instead they are added to "extra Angular modules" as dependencies. Extra Angular modules are created next to its toplevel module: example: search/extramodule.js where all these extra Angular files are added as dependencies.
Notes
Applications are expected to require toplevel Angular modules. When they require more they will also depend on individual Angular files. During migration, the modules of Angular files are added as dependencies both to:
- the "one-ring" ngeo Angular module (legacy);
- its top level or extra module. At the end of the migration we will remove the "one-ring" module (and the associated goog.require and module.dependencies.push code)
How we split / build the code with webpack will be specified later (single build with chunks for gmf apps, examples?, dist...)
The transform to ES6 modules is automatic and has 2 steps:
- transform goog.provide to goog.module
- transform goog.module to ES6 modules. As a consequence, it is not a necessity to transform manually goog.provide to goog.modules
Service filem must export their constructor instead of the Angular module of the service. This is necessary for GCC.
As a consequence their Angular module should be stored in a "module" property of the constructor. Ex:
goog.module('ngeo.MyService'); goog.require('ngeo.module'); exports = class { constructor() { ... } };
const name = 'ngeoMyService'; exports.module = angular.module(name, []).service(name, exports); ngeo.module.requires.push(exports.module.name);
Some services are:
- specific to a task: move to the Angular top level module directory which makes sense.
- a core feature of the library: move to their own Angular top level module directory (ex: permalink -> src/permalink/Permalink.js).
- utilities: move to the src/utils directory (ex: ngeo.utils.File.js)
The permalink service: src/permalink/Permalink.js. The search top level module: src/search/module.js. The search component: src/search/component.js.
- Create you directory in the src/<your_module> (contribs/gmf/src/<your_module>)
- Move your component and eventually the related service ans partial inside this folder
- Rename your component as "component.js", the partial as "component.html", the service as ".js"
- In each file:
- add a
goog.provide('gmf.<module>.<filename>');
- Remove the old goog.provide
- Create your module at the top of the file, right after the requires:
gmf|ngeo.<module>.<filename> = angular.module('<module>', [<here, add dependencies of your component like that: gmf|ngeo.<module>.module.name>]
- if the element must be directly available in the gmf module, push the dependencies in the gmf module like that:
gmf.module.requires.push(gmf.<module>.<filename>.name);
- adapt the name of you class|function like this example: from
ngeo|gmf.element
tongeo|gmf.<module>.<filename>.element_
(the underscore is used to identify easily the element, we will clean it later) - After the creation of your element, register it in your module: `ngeo|gmf...value|service|...|component('', ngeo|gmf...element_)``. Note that the name should be identical as before if possible. Otherwise all call to this element in AngularJS must be adapted...
- add a
- Create a
src/<module>/module.js
file that will define the dependencies of your new module. - Create a
src/<module>/.eslintrc.yaml
file that contains:extends: [../.eslintrc-googshift.yaml]
(to have a nice linter for your module)
Then in the related examples, in the .js :
- Remove the old goog.require and add the new one to your component:
goog.require('gmf|ngeo.<module>.module');
- Add your your module as dependencies in the app|gmfapp:
angular.module('(gmf)app', [..., gmf|ngeo.<module>.module.name,...]
For the applications :
- In the right
src/controllers/abstract.js
, remove the old goog.require and add the new one. - In the
contribs/gmf/apps/appmodule.js
, add your require and your new dependency (withngeo|gmf.<module>.module.name
)
- I'm not sure about the service for the point 6 "partials, services, ... are moved to the directory of their top level Angular module, there are no more "partials" or "services" directories". A service is made to be shared between at least two "things". So, I don't think that make sens to not have a "service" directory. We have services that are only for one component, like the FulltextSearch service. But that's a good example of a bad usage of service. The code can be in the controller directly, the service is useless. [Benjamin]
[Guillaume] {
- the code should be organized in modules/submodules => all what is related to the module should be moved next to it, including partials and services;
- I think it is fine to have a service for only one component (it is actually a best practice in Angular2+); controllers should ideally be minimalistic, but it is unrelated to the ES6 migration; }