Attempt at making Require.js optimization for Magento shops as automatic as possible without having to follow entire Advanced JavaScript bundling guide by hand.
Install with npm:
npm install -g magepack --no-optional
Install with yarn:
yarn global add magepack --ignore-optional
In order to save installation time, disk space and bandwidth on the CI, puppeteer is listed as an optional package because it is only required for configuration generation step.
By design of this module, bundling process is divided into two steps: configuration generation - usually run locally against target environment and bundling which has to be run after deployment of static content is finished.
In order for Require.js optimizer to work properly we need to prepare a configuration for it, which contains following pieces of information:
- Lists of
deps
,paths
,shim
andmap
. - List of
modules
. - Configuration options for optimizer itself.
MagePack is able to extract some of the above automatically from your existing shop website and provides sensible defaults for the rest.
Before running the generation, you have to prepare a small config file, sample for which along with some comments can be found at config.sample.js. This config file will be merged on top of base configuration so it is possible to overwrite any of the defaults.
After preparing the config.js
file (and making sure Puppeteer is installed) we can run the generation process via:
magepack --generate --config config.js --output build.js
which will make the module go through the shop based on config.js
and gather optimizer configuration into build.js
file.
Please note, that in order to achieve best performance the generator extracts all of the common modules used by each group defined within modules
array into separate, synchronously-loaded package.
Once you have generated bundler configuration, the next step would be to trigger the actual optimization after static content deploy stage has finished for every theme and language that is going to be enabled on the storefront:
magepack --bundle --config build.js --dir pub/static/frontend/<vendor>/<theme>/<language>
There may be the case that you would like to some extra modules instead or on top of what is already provided. There are two ways of defining a module:
Plain object compatible with Require.js definition:
modules: [
{
name: 'foo/bar',
create: true,
exclude: ['bundles/common'],
include: ['foo/bar/baz'],
},
];
Asynchronous function that accepts puppeteer's Browser class instance and returns a promise which resolves to above plain object:
modules: [
browser =>
Promise.resolve({
name: 'foo/bar',
create: true,
exclude: ['bundles/common'],
include: ['foo/bar/baz'],
}),
];
Because of below code located within RequireJS:
bundleId = getOwn(bundlesMap, moduleName);
if (bundleId) {
return context.nameToUrl(bundleId, ext, skipExt); // Returns bundle path instead of module path.
}
plugin is not able to properly match given module with its mixins which prevents them from applying. This means that any module which has mixins defined cannot be bundled.
In the early stages there were issues with Magento being unable to properly parse Knockout templates that were inlined by the optimizer so this feature is disabled. I will be revisiting this option soon to check if that obstacle can be resolved.
As far as I understand, because of lack of inlining and CDN usage, text plugin requires additional configuration which this tool writes into requirejs.config.js
when bundling:
requirejs.config({
config: {
text: {
useXhr: function() {
return true;
},
},
},
});
Above lines prevent the plugin from requesting JavaScript versions of required templates resulting in 404 responses.
Because there are already some minified files included in Magento (mainly legacy-build.min.js
) mangling them second time breaks the source code and leads to some random errors. Sadly, there is no way to exclude specific files from this transformation so we had to disable it completely.
Last, but not least the following config has to be added when bundling, otherwise you'll encounter missing dependencies and Cannot access x of undefined
errors:
{
shim: {
'jquery/jquery-migrate': ['jquery', 'jquery/jquery.cookie'],
'fotorama/fotorama': ['jquery'],
},
paths: {
text: 'requirejs/text', // Magento's version of the plugin doesn't support non-browser environment.
mixins: 'mage/requirejs/mixins',
},
}
We use SemVer for versioning. For the versions available, see the tags on this repository.
This project is licensed under the OSL-3.0 license - see the LICENSE.md file for details
- Authors of Advanced JavaScript bundling guide
- Magento Community Engineering Slack.