Skip to content
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

Webpack 5 upgrade #7351

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open

Webpack 5 upgrade #7351

wants to merge 21 commits into from

Conversation

na9da
Copy link
Collaborator

@na9da na9da commented Dec 5, 2024

What this PR does

Fixes #6998
Depends on TerriaJS/TerriaMap#718 and #7311

Upgrades webpack and other build dependencies to the latest version.

Note: bulk of the changes are from running the saas-migrator that upgrades .scss files to modern api.

Changes summary

  • Packages upgraded
    webpack, ...
  • Babel transforms
    • Removed transformation to CJS for the default build. We still use it for node builds.
    • Other transforms removed plugin-proposal-class-properties, proposal-object-rest-spread, plugin-syntax-dynamic-import. These must now be well supported by browsers.
  • Cleaned up configureWebpack.js
    • Removed rules that are no longer necessary
    • Replaced raw-loader file-loader url-loader etc with builtin asset modules
    • Removed use of webpack specific qualifiers for imports like raw-loader!file-loader etc to make it more ESM compliant. Added extra config in webpack to correctly handle imports of static files (like csv and xml).
    • Added rules to polyfill nodejs modules that are referenced from some of our dependencies.
    • Removed hot reload config. AFAICT this was not being used and required maintaining two different code paths in webpack configuration. If required we can add it back later after testing that it works.
    • Replaced multiple configureWebpack parameters with a single options parameter.
    • Removed string-replace-webpack-plugin as it was outdated and has a few vulnerabilities.
      • TODO: Move rewrite of default Cesium API key warning to the app
  • Upgraded SASS
    • Migrated SASS files to use modern API (by running the sass-migrator script)
    • Replaced webpack aliases ~terriajs-variables and ~terriajs-mixins with respective relative path. This was necessary to run the migrator. Also it means simpler webpack config.
    • css-modules-typescript-loader that generates TS types for SASS modules is outdated and no longer works with webpack 5. I have made a repo from a fork of another similar package that can generate types. The other alternative would be to use this TS plugin - but not sure if it'll slow down compilation/editing.
  • Modified TIFFImageryProvider to work with webpack5 build.
  • TODO: Find a replacement for svg-sprite-loader. It appears to be not maintained and has a bunch of audit warnings.
  • Rewrote a couple of specs that depended on some CJS feature
  • TODO: Test in Windows.

I'll annotate the changes to make review easier.

Test me

Checklist

  • There are unit tests to verify my changes are correct or unit tests aren't applicable (if so, write quick reason why unit tests don't exist)
  • I've updated relevant documentation in doc/.
  • I've updated CHANGES.md with what I changed.
  • I've provided instructions in the PR description on how to test this PR.

na9da added 15 commits December 4, 2024 15:28
- Rewrite webpack aliased paths like ~terriajs-variables and ~terriajs-mixins to
  plain relative paths so that we can run the auto migrator.
  This was done using the following shell command:
  ```
     find lib/ -name '*.scss' -exec bash -c 'sed -i "s|~terriajs-variables|$(realpath -s --relative-to=$(dirname "$1") lib/Sass/common/_variables)|" $1' bash  {} \;
  ```
- Run auto migrator
  ```
     find lib/ -name '*.scss' -exec npx sass-migrator module {} \;
  ```
Instead of using 'raw-loader!' etc in the import path, we now
handle these import in webpack config. See webpack.config.make.js.
Removes use of 'raw-loader!' etc in import paths.
Instead handle the imports in webpack config.
Webpack literally works only for 'process.env.NODE_ENV'.
@na9da na9da changed the base branch from main to cjs-to-esm December 5, 2024 01:28
"bottleneck": "^2.19.5",
"catalog-converter": "^0.0.9",
"classnames": "^2.3.1",
"clipboard": "^2.0.8",
"commander": "^11.1.0 ",
"commander": "^12.1.0 ",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit 0a451d1 downgraded commander to 11.1.0 so it would work with node 16.

I'm not against bumping the engine version though, I would prefer to bump engines to node >= 20 so we could "easily" get rid of the security issues in terriajs-server as well while we're at it.

Copy link
Collaborator Author

@na9da na9da Dec 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree that we should bump the engine version, will look into it. In this case though commander is only used for a couple of CLI things and the CI hasn't tripped on it. So it should be fine i guess.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous commander problem that caused the downgrade was most likely fixed by commit 88e587c.

@@ -165,25 +161,22 @@
"react-virtual": "~2.3.2",
"resolve-url-loader": "^5.0.0",
"retry": "^0.12.0",
"sass-loader": "^10",
"sass-loader": "^16.0.3",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fairly sure this also requires bumping the engine version.

@pjonsson
Copy link
Contributor

pjonsson commented Dec 5, 2024

I looked through this and besides the things I commented on, the things that are there looks good to me. Would love to get the (approved) CJS to ESM PR merged soon so this PR doesn't end up in limbo.

@na9da na9da mentioned this pull request Dec 8, 2024
5 tasks
Base automatically changed from cjs-to-esm to main December 8, 2024 23:36
@na9da na9da marked this pull request as ready for review December 8, 2024 23:53
"css-loader": "^2.1.0",
"css-modules-typescript-loader": "^2.0.4",
"css-loader": "^7.1.2",
"terriajs-typings-for-css-modules-loader": "^2.5.2",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-alphabetical sorting, so this package will be shuffled down to the other terriajs-packages the next time someone runs yarn add.

@pjonsson
Copy link
Contributor

pjonsson commented Dec 9, 2024

@na9da just noticed that the late revert of polyfill.js in CJS-to-ESM PR changed the export defaults .. back into the previous module.exports = ....

const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
const ForkTsCheckerNotifierWebpackPlugin = require("fork-ts-checker-notifier-webpack-plugin");
const webpack = require("webpack");

function configureWebpack(
/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@pjonsson
Copy link
Contributor

Since this repository was just converted to ESM, should the other terriajs-repositories (that aren't forks of something else) also be converted to ESM?

I had a look at terriajs-server and it seems quite easy, but I had to upgrade jasmine and yargs.

@na9da
Copy link
Collaborator Author

na9da commented Dec 10, 2024

@na9da just noticed that the late revert of polyfill.js in CJS-to-ESM PR changed the export defaults .. back into the previous module.exports = ....

Yep, i'll make those changes in this PR. I didn't want to create two successive breaking changes.

"babel-plugin-styled-components",
"@babel/plugin-syntax-dynamic-import",
"babel-plugin-lodash"
"babel-plugin-styled-components"
Copy link
Contributor

@pjonsson pjonsson Dec 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anything else controlling babel plugins in the tree, or should the removed babel plugins also be removed from package.json/yarn.lock?

Edit: (I think removing these plugins from package.json/yarn.lock would remove a bunch of warnings, and possibly also remove something from yarn audit so I would love that.)

"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.15.2",
"worker-loader": "^2.0.0"
"webpack": "^5.96.1",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've seen in the upgrade guide that webpack 5 contains types, but it was listed under internal improvements.

If there are type annotations in the webpack 5 package, I'm guessing the types/webpack dev dependency for terriajs should be removed, and if there aren't I'm guessing the types/webpack version should also be bumped to 5.x?

})
);

// Fork TypeScript type checking to a separate thread
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see the fork-ts-checker-webpack-plugin 1.0 had support for webpack 5 alpha back in 2019 according to the release notes, but I'm guessing things have changed in webpack 5 since that time. Should the fork-ts-checker-webpack-plugin and fork-ts-checker-notifier-webpack-plugin be bumped to the latest version at the same time as upgrading to webpack 5?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running yarn gulp build with empty wwwroot/build runtimes:

Webpack 4: 22.3s
Webpack 5 (this branch): 43.8s
Webpack 5 (this branch) + fork-ts-* version 9.x: 21s

so I suggest bumping the versions even if it isn't strictly required.

"babel-plugin-styled-components",
"@babel/plugin-syntax-dynamic-import",
"babel-plugin-lodash"
"babel-plugin-styled-components"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure where this comment fits, but commit dfaf253 added a lib/Core/prerequisites.js which seems to be about compiling to ES5 (which is also what Babel does?).

Should some things be removed from that file as well?

@@ -6,6 +6,7 @@
"engines": {
"node": ">= 16.0.0"
},
"sideEffects": false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read the webpack manual for optimization, and I get the impression this flag helps with reducing the size of the output. Should other terriajs-packages (terriajs-server, thredds-catalog-crawler, etc.) have a package.json that contains sideEffects: false as well?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having read a bit more, I realized a module can be imported for side effects only (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#import_a_module_for_its_side_effects_only), and there seems to be quite a few side effecting imports under lib/:

$ git grep 'import "' lib
lib/Core/polyfill.js:import "core-js/features/promise";
lib/Core/prerequisites.js:import "core-js/features/symbol";
lib/Core/prerequisites.js:import "core-js/features/promise";
lib/Core/prerequisites.js:import "regenerator-runtime/runtime";
lib/Core/prerequisites.js:import "core-js/features/global-this";
lib/Models/GlobeOrMap.ts:import "./Feature/ImageryLayerFeatureInfo"; // overrides Cesium's prototype.configureDescriptionFromProperties
lib/ReactViews/Generic/Editor.jsx:import "!!style-loader!css-loader!./editor.skin.min.css"; // Custom borderless skin
!! TRIMMED tinymce imports in Editor.jsx
lib/ReactViews/Generic/Timer/drawTimer.js:import "d3-transition";
lib/ReactViews/StandardUserInterface/StandardUserInterface.tsx:import "inobounce";
lib/ReactViews/Workbench/WorkbenchList.tsx:import "!!style-loader!css-loader!./sortable.css";
lib/ThirdParty/urijs/index.d.ts:import "urijs/src/URITemplate";
  • polyfill/prerequisites: Used by TerriaMap. The point of both polyfill and prerequisites seems to be to "pollute" the global namespace with compatibility functions for browsers that do not support them natively (both "Tip" boxes under https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free), won't that functionality break for TerriaMap when setting sideEffects: false?
  • css-imports in Editor and WorkbenchList: I'm guessing second tip box from the link in the previous bullet applies to these?
  • GlobeOrMap: the only place that overrides ImageryLayerFeatureInfo. Can the side-effecting import be eliminated by just putting the 38 lines from the imported file directly into GlobeOrMap?
  • Editor: lots of side effecting imports of tinymce modules, and then Editor is imported lazily by StoryEditor.jsx. Don't understand the details, but looks fragile in general.
  • drawTimer: commit 9035320 added the import in 2019 to "fix the buses layer". I don't know what the "buses layer" is, but the versions of the d3-packages were updated in 2024, so it might be possible to change the import to something more specific now.
  • StandardUserInterface: inobounce seems to be a function called from the top level, not sure this can be avoided.
  • ThirdParty/urijs: Update types/urijs #7435 removes this.

);
import mapConfigBasicJson from "../../wwwroot/test/Magda/map-config-basic.json";
import mapConfigV7Json from "../../wwwroot/test/Magda/map-config-v7.json";
import mapConfigInlineInitJson from "../../wwwroot/test/Magda/map-config-inline-init.json";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I run yarn gulp build on this branch, I get this warning just above the prompt after the build completes:

WARNING in ./node_modules/terriajs-cesium/Source/Core/buildModuleUrl.js 50:37-48
Critical dependency: Accessing import.meta directly is unsupported (only property access or destructuring is supported)
 @ ./test/Models/TerriaSpec.ts 41:0-72 113:13-27 118:13-27

@@ -1 +1 @@
module.exports = require("./webpack.config.make")(false, true);
module.exports = require("./webpack.config.make")(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This config disables devMode, was the wrong parameter removed?

include: path.resolve(cesiumDir, "Source", "Assets"),
loader: require.resolve("file-loader"),
type: "javascript/auto"
test: /\.(DAC)$/i,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the parenthesis can be omitted, so /\.DAC$/i should be enough.

include: path.resolve(cesiumDir, "Source", "ThirdParty"),
loader: require.resolve("file-loader"),
type: "javascript/auto"
test: /\.(css)$/i,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this parenthesis can be omitted too, so /\.css$/i should be enough.

// import "!!style-loader!css-loader?sourceMap!tinymce/skins/ui/oxide/skin.min.css";
import "!!style-loader!css-loader?sourceMap!./editor.skin.min.css"; // Custom borderless skin
// import "!!style-loader!css-loader!tinymce/skins/ui/oxide/skin.min.css";
import "!!style-loader!css-loader!./editor.skin.min.css"; // Custom borderless skin
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The style-loader seems to have been removed from the webpack config, do these imports work as intended despite that?

@@ -6,6 +6,7 @@
"engines": {
"node": ">= 16.0.0"
},
"sideEffects": false,
"repository": {
"type": "git",
"url": "http://github.com/TerriaJS/terriajs"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a resolution of terser-webpack-plugin to version 4 a few lines below (introduced in commit 5b27cb2). You might be able to drop the resolution, or at least update the resolution to version 5.

@import "~terriajs-variables";
@import "../../../../Sass/common/mixins";
@use "../../../../Sass/common/_variables";
@use "../../../../Sass/common/mixins";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these files import mixins, and others import _mixins (see guidance-dot.scss vs this file, both in subdirectories of ReactViews), is that intentional?

@pjonsson
Copy link
Contributor

pjonsson commented Dec 29, 2024

* Cleaned up configureWebpack.js
  
  * Removed rules that are no longer necessary

This is great, navigating around old unused things is confusing for newcomers.

  * Replaced multiple `configureWebpack` parameters with a single options parameter.

I don't understand this change in general; the parameters are packed into a record at the caller and then immediately unpacked in the arguments of the callee, so the change is effectively adding braces around what was there previously. I also get a complaint that the JSDoc is invalid because it references options.x but does not contain the correct @param options, and a complaint on the caller that it's missing the babelLoader parameter expected by the function. For languages I know, I usually enable some extra checks in my IDE, but these complaints are with the default settings.

  * Removed `string-replace-webpack-plugin` as it was outdated and has a few vulnerabilities.
    
    * [ ]  TODO: Move rewrite of default Cesium API key warning to the app

I'm all for improved security so I love this, but just updating to Webpack 5 fixes a bunch of vulnerabilities, and this PR blocks a lot of other things. Can the plugin be used with Webpack 5 so this PR can get merged first, and you then do this rewrite in a separate PR?

Edit: I just realized terriajs keeps a fork of Cesium. Isn't it easiest to change the message in that fork, and not rewrite anything at build time?

* Upgraded SASS
  
  * `css-modules-typescript-loader` that generates TS types for SASS modules is outdated and no longer works with webpack 5. I have made a [repo](https://github.com/TerriaJS/terriajs-typings-for-css-modules-loader) from a [fork of another similar package](https://github.com/TeamSupercell/typings-for-css-modules-loader/pull/93) that can generate types. The other alternative would be to use this [TS plugin](https://www.npmjs.com/package/typescript-plugin-css-modules) - but not sure if it'll slow down compilation/editing.

I had no idea how things were built before looking at this PR and I'm not thrilled about how the generated scss.d.ts files are committed to the repository (we've been trying to build things in separate build directories for 20+ years with autoconf/CMake), but I had a look at some sibling package of the linked TS plugin trying to figure out what was wrong with related-maps.scss (#7427), and what you've done here is far better than the listed alternatives.

* [ ]  TODO: Find a replacement for `svg-sprite-loader`. It appears to be not maintained and has a bunch of audit warnings.

If the plugin works with Webpack 5, I think that should be handled in a separate PR because this PR in its current form brings a lot of improvements already.

});

// Remove Cesium debug mode checks in production. This might slightly improve performance.
// TODO: It will be good to have it enabled in devMode though, to discover issues with code
// however doing so currently breaks a few specs.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#7433 and #7439.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Upgrade to webpack 5
3 participants