-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[TR-6197] Moving from AMD to ESM #190
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code changes look alright.
I'm pretty sure the reason tests are failing is due to async
version upgrade. I checked out develop versions of package.json and package-lock, installed them (tests passed), then installed async@3
(tests failed).
I guess it is related to the following dependency chain, but I can't explain the precise error:
npm ls async
@oat-sa/tao-core-sdk@3.2.1
├── async@3.2.6
└─┬ handlebars@1.3.0
└─┬ uglify-js@2.3.6
└── async@0.2.10
package.json
Outdated
@@ -47,11 +52,11 @@ | |||
"@oat-sa/eslint-config-tao": "^2.0.0", | |||
"@oat-sa/prettier-config": "^0.1.1", | |||
"@oat-sa/tao-qunit-testrunner": "^2.0.0", | |||
"async": "^0.2.10", | |||
"async": "^3.2.6", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe there was a specific reason we kept the async 0.x
version for so long.
If the 3.x version is 100% equivalent, that's great, but we must be absolutely sure of it.
I'm not even sure where it is used in this library - need to check history books and see if another part of the TAO ecosystem breaks...
package.json
Outdated
"eslint": "^8.39.0", | ||
"fetch-mock": "^9.11.0", | ||
"glob": "^8.1.0", | ||
"handlebars": "1.3.0", | ||
"handlebars": "4.7.7", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For handlebars I don't think we can upgrade this easily. It requires a big effort to synchronise across all TAO 3.x repos, see https://oat-sa.atlassian.net/wiki/spaces/FOUN/pages/144081031/Upgrade+Handlebars (a task which ended up blocked the last 2 times).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a few comments. Mainly my concern is regarding the replacement of URI with relative paths.
I'm not sure it will work fine with TAO Terre, which still uses AMD. Moreover, if you want a proper handling of ESM, every import should have the file extension. Here again, I'm not sure about the impact on the AMD consumers.
update: Ok, this is required by the ticket, actually. While it is worth checking with the Terre consumers, we should also add the file extension to each import as this is recommended by the standard and required by Vite.
I see you did convert some files to ES6, which is nice, but then why is it half way?
src/core/asyncProcess.js
Outdated
import Promise from './promise'; | ||
import eventifier from './eventifier'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: I don't think the URI can be changed. Remember, the consumer still needs to access AMD-compatible URIs. Renaming the routes may create issues. I'm curious to know why such a change is necessary.
update: Ok, this is required by the ticket, actually. While it is worth checking with the Terre consumers, we should also add the file extension to each import as this is recommended by the standard and required by Vite.
src/core/asyncProcess.js
Outdated
@@ -52,7 +52,7 @@ function asyncProcessFactory() { | |||
* @returns {boolean} - Returns true if the process can be started | |||
*/ | |||
start: function start(cb) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
quibble: Converting the code to use let
and const
instead of var
is good, but why not continue and also use the shorthand?
start: function start(cb) { | |
start(cb) { |
src/core/filter/filters.js
Outdated
var Filters = { | ||
register: function(name, filter) { | ||
const Filters = { | ||
register: function (name, filter) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
register: function (name, filter) { | |
register(name, filter) { |
@@ -53,8 +52,8 @@ var allowedEvents = [ | |||
* @param {*} eventOptions | |||
* @returns {Event} | |||
*/ | |||
var createEvent = function createEvent(eventName, eventOptions) { | |||
var event; | |||
const createEvent = function createEvent(eventName, eventOptions) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
quibble: Converting the code to use let
and const
instead of var
is good, but why not continue and also the correct pattern for functions?
Usually, when you see var something = function() { ... }
, this is either a developer's taste (which is IMO debatable), or because the function needs to be redefined later on. If the function is immutable, then the best practice is to use a named function instead of const something = function() { ... }
. Why? because function
hoists, while const
is lexically scoped. This also removes redundant and cumbersome naming.
suggestion:
const createEvent = function createEvent(eventName, eventOptions) { | |
function createEvent(eventName, eventOptions) { |
build/rollup.config.js
Outdated
@@ -25,7 +25,7 @@ import commonJS from 'rollup-plugin-commonjs'; | |||
import babel from 'rollup-plugin-babel'; | |||
import istanbul from 'rollup-plugin-istanbul'; | |||
|
|||
const { srcDir, outputDir } = require('./path'); | |||
import { srcDir, outputDir } from "./path"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import { srcDir, outputDir } from "./path"; | |
import { srcDir, outputDir } from "./path.js"; |
src/core/asyncProcess.js
Outdated
import Promise from './promise'; | ||
import eventifier from './eventifier'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: to properly follow the requirements, we also need to add the file extension
import Promise from './promise'; | |
import eventifier from './eventifier'; | |
import Promise from './promise.js'; | |
import eventifier from './eventifier.js'; |
src/core/asyncProcess.js
Outdated
*/ | ||
/** | ||
* @author Jean-Sébastien Conan <jean-sebastien.conan@vesperiagroup.com> | ||
*/ | ||
import _ from 'lodash'; | ||
import Promise from 'core/promise'; | ||
import eventifier from 'core/eventifier'; | ||
import Promise from './promise'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
question: Is this still needed? Promise
was polyfilled, but it has been natively supported since ages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
build/path.js
Outdated
@@ -19,12 +19,10 @@ | |||
/** | |||
* This file contains path definitions for build scripts. | |||
*/ | |||
const path = require('path'); | |||
import path from "path"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use single quotes
build/rollup.config.js
Outdated
@@ -25,7 +25,7 @@ import commonJS from 'rollup-plugin-commonjs'; | |||
import babel from 'rollup-plugin-babel'; | |||
import istanbul from 'rollup-plugin-istanbul'; | |||
|
|||
const { srcDir, outputDir } = require('./path'); | |||
import { srcDir, outputDir } from "./path.js"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use single quotes
src/core/collections.js
Outdated
@@ -13,7 +13,7 @@ | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
* | |||
* Copyright (c) 2016-2019 Open Assessment Technologies SA | |||
* Copyright (c) 2016-2024 Open Assessment Technologies SA |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rollback
src/core/customEvent.js
Outdated
@@ -13,7 +13,7 @@ | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
* | |||
* Copyright (c) 2015-2019 (original work) Open Assessment Technologies SA ; | |||
* Copyright (c) 2015-2024 (original work) Open Assessment Technologies SA ; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rollback
src/core/dataattrhandler.js
Outdated
@@ -13,7 +13,7 @@ | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
* | |||
* Copyright (c) 2013-2019 (original work) Open Assessment Technologies SA ; | |||
* Copyright (c) 2013-2024 (original work) Open Assessment Technologies SA ; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rollback
src/util/locale.js
Outdated
@@ -13,7 +13,7 @@ | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
* | |||
* Copyright (c) 2016-2021 (original work) Open Assessment Technologies SA; | |||
* Copyright (c) 2016-2024 (original work) Open Assessment Technologies SA; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rollback file
src/util/regexEscape.js
Outdated
@@ -13,7 +13,7 @@ | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
* | |||
* Copyright (c) 2015-2019 (original work) Open Assessment Technologies SA ; | |||
* Copyright (c) 2015-2024 (original work) Open Assessment Technologies SA ; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rollback file
src/util/strLimiter.js
Outdated
@@ -13,7 +13,7 @@ | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
* | |||
* Copyright (c) 2018-2022 Open Assessment Technologies SA | |||
* Copyright (c) 2018-2024 Open Assessment Technologies SA |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rollback file
src/util/url.js
Outdated
@@ -13,7 +13,7 @@ | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
* | |||
* Copyright (c) 2015-2019 (original work) Open Assessment Technologies SA; | |||
* Copyright (c) 2015-2024 (original work) Open Assessment Technologies SA; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rollback file
src/util/urlParser.js
Outdated
@@ -13,7 +13,7 @@ | |||
* along with this program; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
* | |||
* Copyright (c) 2013-2019 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); | |||
* Copyright (c) 2013-2024 (original work) Open Assessment Technologies SA (under the project TAO-PRODUCT); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rollback file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see some of the tests, after refactoring, do not seem to test the useful things any more.
You've done this to avoid failures based on ESM dependency module state?
I wonder if we should remove more, or take a deeper look into how to fix the testing set-up to pass.
@jsconan do you have any thoughts on this?
assert.ok(false, 'The promise should not be rejected'); | ||
// eslint-disable-next-line | ||
console.error(err); | ||
.catch(function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it mean the result
Promise previously resolved but now rejects?
If that's the case, it's testing the opposite of what's expected.
Is this test worth having any more?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mocking with current way is not possible on ESM implementation, so now call always falling. I left this catch because this promise chain is required to keep previous asserts working.
I can move ready
state to previous then
block as consensuses.
assert.ok(false, 'The promise should not be rejected'); | ||
// eslint-disable-next-line | ||
console.error(err); | ||
.catch(function () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above, should it really go into a catch
to complete the test?
When I run the tests I get a list of tests passing and then
Am I the only one? |
@KirylHatalski we also need to know if there has been a successful install of the new package in TAO 3.x. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- New code is covered by tests (if applicable)
- Tests are running successfully (old and new ones) on my local machine (if applicable)
- New code is respecting code style rules
- New code is respecting best practices
- New code is not subject to concurrency issues (if applicable)
- Feature is working correctly on my local machine (if applicable)
- Acceptance criteria are respected
- Pull request title and description are meaningful
Package published as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Version 4.0.0-alpha.1
was released. I tried it in control center and it didn't work.
My idea was that we could remove this moduleLoader mock that we use in all our apps and also remove this line, to help the bundler (rolllup/vite) resolve the import from 'core/.../
;` lines.
[{ find: 'core/moduleLoader', replacement: path.resolve(srcDir, 'core', 'moduleLoader') }](https://github.com/oat-sa/tao-control-center/blob/develop/frontend/vite.config.js#L52)
If I remove the mock from my project and install version 4.0.0-alpha.1
I get this error in the console. The logger module isn't found.
In the sdk code I see
return Promise.all(
amdModules.map(module => import(/* webpackIgnore: true */ `${module}`))
).then(loadedModules => loadedModules.map(module => module.default));
I don't think that will work in ESM, since import('${module}')
is trying to import a variable value, but that wouldn't work in a dynamic import. The import needs a string literal. That's why we have this in our moduleLoader mock
return Promise.all(
amdModules.map(mod => {
switch (mod) {
case 'core/logger/console':
return import('core/logger/console');
}
})
).then(loadedModules => loadedModules.map(res => res && res.default));
So import('core/logger/console')
works if we have
{
find: 'core',
replacement: path.resolve(nodeModulesRoot, '@oat-sa', 'tao-core-sdk', 'src', 'core')
},
in our app config, to help the bundler find the 'core/logger/console'
module. But if we want to remove all the extra config what we need for it to work as a ESM package is
return Promise.all(
amdModules.map(mod => {
switch (mod) {
case 'core/logger/console':
return import('./logger/console');
}
})
).then(loadedModules => loadedModules.map(res => res && res.default));
which is the relative path to the ./logger/console.js
file. So maybe a solution to this, compatible with AMD and ESM would be:
const loadModules = (amdModules = []) => {
if (_.isArray(amdModules) && amdModules.length) {
if (typeof window.define === 'function' && window.define.amd) {
return new Promise((resolve, reject) => {
window.require(
amdModules,
(...loadedModules) => resolve(loadedModules),
err => {
reject(err);
}
);
});
} else {
return Promise.all(
amdModules.map(mod => {
switch (mod) {
case 'core/logger/console':
return import('./logger/console');
}
})
).then(loadedModules => loadedModules.map(res => res && res.default));
}
}
return Promise.resolve();
};
Version❕ Some commits are not using the conventional commits formats. They will be ignored in version management.
There are 0 BREAKING CHANGE, 0 feature, 0 fix |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code looks good.
Pay attention to some "typos" that you fixed that were not typos and that now are... 😄
Regarding the overall change, it does not work fine with TAO where multiple modules cannot load. Maybe is there something missing to update on TAO, but the PR description is pretty terse regarding the change...
@@ -53,7 +53,7 @@ const logger = loggerFactory('core/request'); | |||
* @param {Object} response - the server body response as plain object | |||
* @param {String} fallbackMessage - the error message in case the response isn't correct | |||
* @param {Number} httpCode - the response HTTP code | |||
* @param {Boolean} httpSent - the sent status | |||
* @param {Boolean} httpSent - the scent status |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chore: Funny, but not accurate! Computers cannot smell... 🤣
@@ -28,7 +27,7 @@ import Promise from 'core/promise'; | |||
function requireIfExists(uri) { | |||
// the promise will always be resolved | |||
return new Promise(function(resolve) { | |||
// if a require issue occurs, fallback to an empty resource | |||
// if a requirement issue occurs, fallback to an empty resource |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chore: I think the initial term was good: when the require
API fails...
Ticket: TR-6197