Open robyngit opened 1 year ago
Note that RequireJS also has an optimization tool that we have considered using in the past.
app.js
. The real entry point is index.html
which loads loader.js
which loads app.js
.require-text
can be replaced with text-loader
to load templates.component
external, and just bundle the MetacatUI code.loader.js
file is bundled at the moment. He triggers webpack to build from the server.js
file using webpack-hot-middleware
and webpack-dev-middleware
.TL;DR: Good news: Minifying with Gulp is very easy. Bad news: Minifying the JS files has little impact on performance.
Setting up Gulp to minify the JS was very straight-forward compared to attempting to bundle and minify with Webpack.
Install Gulp Globally (optional, but makes it easier to run gulp from the command line):
npm install -g gulp-cli
Install Gulp Locally:
npm install --save-dev gulp
Install Required Gulp Plugins:
Install the gulp-terser
and gulp-tap
plugins using npm.
npm install --save-dev gulp-terser gulp-tap
Create The Gulpfile (gulpfile.js
):
const gulp = require('gulp');
const terser = require('gulp-terser');
const tap = require('gulp-tap');
gulp.task('copy-all', function() {
// Copy all files from src to dist
return gulp.src('src/**/*')
.pipe(gulp.dest('dist'));
});
gulp.task('minify-js', function() {
return gulp.src('dist/**/*.js')
.pipe(tap(function(file) {
return gulp.src(file.path, { base: 'dist' })
.pipe(terser())
.on('error', function(err) {
console.warn(`Error in file ${file.path}: ${err.toString()}`);
this.emit('end');
})
.pipe(gulp.dest('dist')); // Save it back to the dist directory
}));
});
gulp.task('build', gulp.series('copy-all', 'minify-js'));
Run the Build Task:
Execute the build task to copy all files from src/
to dist/
and then minify all JavaScript files.
gulp build
Switch the dev server to run from dist
rather than src
:
In server.js
switch const src_dir = "src";
to const src_dir = "dist";
I ran Chrome's lighthouse test twice: once with files served from src
(unminified JS), and once files saved from dist
(minified JS). The difference in performance was disappointing:
I think the recommendations detailed by Lauren are the tasks we should focus on in order to improve performance.
In considering Issue#224:
I've spent some time trying to see what it would take to migrate to a tool like Webpack. I think it would required migrating from require.js style modules to ES6 modules first. In the meantime, the r.js tool for optimizing and bundling does seem to be a significantly easier effort. I have a branch in my fork of this repo where I've used r.js to create one single bundle file that could be loaded in production instead (the commit). On my local machine this takes me from loading 186 JavaScript files (186 http requests) to loading only 17. I haven't been able to get minification to work (the single JS file is almost 8MB!!) but I think with some more effort it should be possible to figure out the remaining issues that are blocking that.
Nice! Thank you for looking more into this @ianguerin. Did you measure or notice any differences in load time? I'd guess even with minification, those 17 files might be too large
I did not see a significant overall "score" using the Chrome DevTools Lighthouse extension, though it did get better. I did see an increase in time to first contentful load (bad) I've attached my two lighthouse runs below, before my changes and after my changes.
I wouldn't recommend going through this risky of a change for such a minor improvement, but I think playing around with some of the configuration rules, maybe [modules
configuration for r.js] (https://github.com/requirejs/r.js/blob/acec5366eb9094e670b6d1a87457634e74d6384e/build/example.build.js#L355) could be beneficial, and this commit has at least a PoC to getting that to work.
MetacatUI currently relies on RequireJS for asset loading. We aim to improve performance by integrating a modern bundler such as Webpack or Parcel. The goal is to improve MetacatUI's performance and load time through minification, uglification, and bundling of JavaScript files and other assets (e.g. CSS files), as well as code-splitting and tree-shaking techniques.
Although we would eventually like to replace RequireJS with ES6 modules, as a first step, we want RequireJS to co-exist with the new bundler. This way, we preserve full backward compatibility, allowing repositories to choose whether or not to adopt the new build system. Likely, the bundled code will be organized in a new
/dist/
directory, distinct from the current/src/
directory.Considerations:
Metrics for Evaluating App Performance:
To measure the success of performance improvements, we can focus on:
Criteria for Choosing a Bundler
Must-Have:
Nice-to-Have:
Bundler Options
Two bundlers seem to be the most promising candidates:
Bundlers ruled out:
Next Steps