Skip to content

Commit

Permalink
build: set AMD module module names within UMD bundles
Browse files Browse the repository at this point in the history
Currently if the UMD bundles from `@material/<..>` NPM modules are
loaded in the browser, using RequireJS or other loaders, the
AMD modules would need to be named manually using a loader
configuration. e.g.

```js
require.config({
  paths: {
      '@material/animation': '/base/npm/node_modules/@material/animation/dist/mdc.animation',
      ...
  }
}
```

This could be avoided if the AMD `define` invocations in the UMD file
would specify a module id, similar to how it's done in packages of the
Angular organization. This allows for easier consumption in tests as well.

Note that this change causes a breaking change for the UMD-case where
the exports are bound to a global variable. Previously the entry-point
would appear in camel-case, but now it's matching the actual package
name in dash-case. This is unfortunately not avoidable with the current
Webpack tooling. i.e. previous UMD users relying on the globals (which are
rather rare anyway), would need to switch from
`window.mdc.circularProgress` to `window.mdc['circular-progress]`.
  • Loading branch information
devversion committed Jul 15, 2021
1 parent 22d29cb commit c0e7353
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 41 deletions.
4 changes: 2 additions & 2 deletions scripts/check-pkg-for-release.js
Expand Up @@ -143,10 +143,10 @@ function checkJSDependencyAddedInWebpackConfig() {
const jsconfig = WEBPACK_CONFIG.find((value) => {
return value.name === 'main-js-a-la-carte';
});
const nameCamel = camelCase(CLI_PACKAGE_JSON.name.replace('@material/', ''));
const pkgName = CLI_PACKAGE_JSON.name.replace('@material/', '');
assert.notEqual(typeof jsconfig.entry[nameCamel], 'undefined',
'FAILURE: Component ' + CLI_PACKAGE_JSON.name + ' javascript dependency is not added to webpack ' +
'configuration. Please add ' + nameCamel + ' to ' + WEBPACK_CONFIG_RELATIVE_PATH + '\'s js-components ' +
'configuration. Please add ' + pkgName + ' to ' + WEBPACK_CONFIG_RELATIVE_PATH + '\'s js-components ' +
'entry before commit. If package @material/' + name + ' has no exported JS, add "' + name + '" to ' +
'the JS_EXCLUDES set in this file.');
}
Expand Down
100 changes: 61 additions & 39 deletions scripts/webpack/js-bundle-factory.js
Expand Up @@ -63,7 +63,7 @@ class JsBundleFactory {
fsDirAbsolutePath = undefined, // Required for building the npm distribution and writing output files to disk
httpDirAbsolutePath = undefined, // Required for running the demo server
filenamePattern = this.env_.isProd() ? '[name].min.js' : '[name].js',
library,
moduleName: {root, amd},
globalObject = 'this',
},
plugins = [],
Expand Down Expand Up @@ -95,9 +95,17 @@ class JsBundleFactory {
output: {
path: fsDirAbsolutePath,
publicPath: httpDirAbsolutePath,
filename: filenamePattern,
// Webpack does not allow us to set custom placeholders, so we need to use a function here to
// manually replace `[name]` with a camel-cased variant. e.g. `auto-init.js` should become `autoInit.js`.
// Unfortunately we cannot set the chunk names directly to a camel-cased variant because that would
// break the AMD module names then (which should match the NPM package names. e.g. `@material/auto-init`).
filename: ({chunk: {name}}) => filenamePattern.replace(/\[name]/g, toCamelCase(name)),
libraryTarget: 'umd',
library,
library: {
root,
amd,
},
umdNamedDefine: true,
globalObject,
},
resolve: {extensions},
Expand Down Expand Up @@ -147,7 +155,10 @@ class JsBundleFactory {
fsDirAbsolutePath,
httpDirAbsolutePath,
filenamePattern: this.env_.isProd() ? 'material-components-web.min.js' : 'material-components-web.js',
library: 'mdc',
moduleName: {
amd: 'material-components-web',
root: ['mdc']
},
},
plugins,
});
Expand All @@ -166,50 +177,61 @@ class JsBundleFactory {
return this.createCustomJs({
bundleName: 'main-js-a-la-carte',
chunks: {
animation: getAbsolutePath('/packages/mdc-animation/index.ts'),
autoInit: getAbsolutePath('/packages/mdc-auto-init/index.ts'),
banner: getAbsolutePath('/packages/mdc-banner/index.ts'),
base: getAbsolutePath('/packages/mdc-base/index.ts'),
checkbox: getAbsolutePath('/packages/mdc-checkbox/index.ts'),
chips: getAbsolutePath('/packages/mdc-chips/index.ts'),
circularProgress: getAbsolutePath('packages/mdc-circular-progress/index.ts'),
dataTable: getAbsolutePath('/packages/mdc-data-table/index.ts'),
dialog: getAbsolutePath('/packages/mdc-dialog/index.ts'),
dom: getAbsolutePath('/packages/mdc-dom/index.ts'),
drawer: getAbsolutePath('/packages/mdc-drawer/index.ts'),
floatingLabel: getAbsolutePath('/packages/mdc-floating-label/index.ts'),
formField: getAbsolutePath('/packages/mdc-form-field/index.ts'),
iconButton: getAbsolutePath('/packages/mdc-icon-button/index.ts'),
list: getAbsolutePath('/packages/mdc-list/index.ts'),
lineRipple: getAbsolutePath('/packages/mdc-line-ripple/index.ts'),
linearProgress: getAbsolutePath('/packages/mdc-linear-progress/index.ts'),
menu: getAbsolutePath('/packages/mdc-menu/index.ts'),
menuSurface: getAbsolutePath('/packages/mdc-menu-surface/index.ts'),
notchedOutline: getAbsolutePath('/packages/mdc-notched-outline/index.ts'),
radio: getAbsolutePath('/packages/mdc-radio/index.ts'),
ripple: getAbsolutePath('/packages/mdc-ripple/index.ts'),
segmentedButton: getAbsolutePath('/packages/mdc-segmented-button/index.ts'),
select: getAbsolutePath('/packages/mdc-select/index.ts'),
slider: getAbsolutePath('/packages/mdc-slider/index.ts'),
snackbar: getAbsolutePath('/packages/mdc-snackbar/index.ts'),
switch: getAbsolutePath('/packages/mdc-switch/index.ts'),
tab: getAbsolutePath('/packages/mdc-tab/index.ts'),
tabBar: getAbsolutePath('/packages/mdc-tab-bar/index.ts'),
tabIndicator: getAbsolutePath('/packages/mdc-tab-indicator/index.ts'),
tabScroller: getAbsolutePath('/packages/mdc-tab-scroller/index.ts'),
textfield: getAbsolutePath('/packages/mdc-textfield/index.ts'),
tooltip: getAbsolutePath('/packages/mdc-tooltip/index.ts'),
topAppBar: getAbsolutePath('/packages/mdc-top-app-bar/index.ts'),
'animation': getAbsolutePath('/packages/mdc-animation/index.ts'),
'auto-init': getAbsolutePath('/packages/mdc-auto-init/index.ts'),
'banner': getAbsolutePath('/packages/mdc-banner/index.ts'),
'base': getAbsolutePath('/packages/mdc-base/index.ts'),
'checkbox': getAbsolutePath('/packages/mdc-checkbox/index.ts'),
'chips': getAbsolutePath('/packages/mdc-chips/index.ts'),
'circular-progress': getAbsolutePath('packages/mdc-circular-progress/index.ts'),
'data-table': getAbsolutePath('/packages/mdc-data-table/index.ts'),
'dialog': getAbsolutePath('/packages/mdc-dialog/index.ts'),
'dom': getAbsolutePath('/packages/mdc-dom/index.ts'),
'drawer': getAbsolutePath('/packages/mdc-drawer/index.ts'),
'floating-label': getAbsolutePath('/packages/mdc-floating-label/index.ts'),
'form-field': getAbsolutePath('/packages/mdc-form-field/index.ts'),
'icon-button': getAbsolutePath('/packages/mdc-icon-button/index.ts'),
'list': getAbsolutePath('/packages/mdc-list/index.ts'),
'line-ripple': getAbsolutePath('/packages/mdc-line-ripple/index.ts'),
'linear-progress': getAbsolutePath('/packages/mdc-linear-progress/index.ts'),
'menu': getAbsolutePath('/packages/mdc-menu/index.ts'),
'menu-surface': getAbsolutePath('/packages/mdc-menu-surface/index.ts'),
'notched-outline': getAbsolutePath('/packages/mdc-notched-outline/index.ts'),
'radio': getAbsolutePath('/packages/mdc-radio/index.ts'),
'ripple': getAbsolutePath('/packages/mdc-ripple/index.ts'),
'segmented-button': getAbsolutePath('/packages/mdc-segmented-button/index.ts'),
'select': getAbsolutePath('/packages/mdc-select/index.ts'),
'slider': getAbsolutePath('/packages/mdc-slider/index.ts'),
'snackbar': getAbsolutePath('/packages/mdc-snackbar/index.ts'),
'switch': getAbsolutePath('/packages/mdc-switch/index.ts'),
'tab': getAbsolutePath('/packages/mdc-tab/index.ts'),
'tab-bar': getAbsolutePath('/packages/mdc-tab-bar/index.ts'),
'tab-indicator': getAbsolutePath('/packages/mdc-tab-indicator/index.ts'),
'tab-scroller': getAbsolutePath('/packages/mdc-tab-scroller/index.ts'),
'textfield': getAbsolutePath('/packages/mdc-textfield/index.ts'),
'tooltip': getAbsolutePath('/packages/mdc-tooltip/index.ts'),
'top-app-bar': getAbsolutePath('/packages/mdc-top-app-bar/index.ts'),
},
output: {
fsDirAbsolutePath,
httpDirAbsolutePath,
filenamePattern: this.env_.isProd() ? 'mdc.[name].min.js' : 'mdc.[name].js',
library: ['mdc', '[name]'],
moduleName: {
amd: '@material/[name]',
root: ['mdc', '[name]'],
},
},
plugins,
});
}
}

/**
* @param {string} dashedName A dash-separated package name. E.g., "mdc-linear-progress".
* @return {string} dashedName converted to camelCase. E.g., "mdcLinearProgress".
*/
function toCamelCase(dashedName) {
return dashedName.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
}

module.exports = JsBundleFactory;

0 comments on commit c0e7353

Please sign in to comment.