Frontend Developer Manual / Version 2307
Table Of ContentsNot all JavaScript files found via the NPM registry are written with a JavaScript Module System in mind. This might also apply to your own JavaScript if you are coming from an older CoreMedia version. One of the main differences between modular and non-modular JavaScript is the scope of the declared variables. While the latter has full access to global variables modular JavaScript will never work on the global scope but will import other modules if functionality is needed and exports its own functionality that can be reused by other modules explicitly.
First of all, CoreMedia recommends to actually migrate non-modular JavaScript into modular JavaScript, preferable by using the ES6 module system. This makes sure that all JavaScripts are up-to-date and you can use the advantages of the module system. IDEs like IntelliJ IDEA offer very good code assistance to efficiently work with the module systems.
However, in some cases migration is not possible because the JavaScript comes from a third-party library and may not
be changed or it is too expensive to perform a full migration of the existing code base. In both cases the suggested
approach is to use a mechanism called Shimming
which basically means wrapping the JavaScript into an
adapter that - from the perspective of the module system - makes sure that the JavaScript can be used as a module but
- from the perspective of the JavaScript file - provides access to all global variables the file is operating on.
Shimming
Shimming is build into the theme build mechanism based on Webpack's imports-loader and exports-loader. Make sure you have read the basic concepts described in the Webpack Documentation.
Let's imaging there is a third-party JavaScript ./src/vendor/specialCalc.js
that expects jQuery
to be found under a global variable named jQuery
. It will perform some calculations and stores its
result in a global variable named calculationResult
. This JavaScript file may not be touched because the
author doesn't think it is a good idea to use a modular system but still provides updates regularly to improve the
algorithm of the calculation. To integrate this JavaScript file into a modular system you need to shim it. This
can be achieved in two ways.
Shimming via Webpack Configuration
In a theme you can directly adjust your webpack.config.js
to add configuration for shimming:
const path = require("path"); const { webpackConfig } = require("@coremedia/theme-utils/webpack.config.js"); module.exports = (env, argv) => { const config = webpackConfig(env, argv); config.module = config.module || {}; config.module.rules = config.module.rules || []; config.module.rules.push({ test: path.resolve("./src/vendor/specialCalc.js"), use: ["imports-loader?jQuery=jquery", "exports-loader?result=calculationResult"], }); return config; };
Example 5.3. Shimming in webpack.config.js
This means that whenever ./src/vendor/specialCalc.js
is imported by a JavaScript module the
module known as jquery
will be provided under a variable named jQuery
. After the script
has run a variable named calculationResult
will be exported under the name result
.
Basically the mechanism will add code to the beginning and to the end of the JavaScript file during theme build, so the resulting output looks like this and can be used as a JavaScript module:
import jQuery from "jquery"; ... (the original code of specialCalc.js) ... export { calculationResult as result };
Example 5.4. The added code
Shimming via package.json
You can also add a shim
configuration in your theme configuration. This also works in bricks so they
can provide their required shimming configuration self-contained:
{ ... "coremedia": { "type: "theme", ... "shim": { "./src/vendor/jquery.bcSwipe": { "imports": { "jQuery": "jquery" }, "exports": { "": "jQuery" } } } } }
Example 5.5. Shimming in the theme's package.json
This will lead to the same result as the other example.
Warning
Although it is also possible to shim a module on the fly during a require
statement directly in the
JavaScript that wants to import a non-modular JavaScript file CoreMedia does not recommend using it. The syntax is hard to
read but more important it will break the externals
configuration as modules are imported although they are marked as external dependency.