Webpack loaders and plugins used by the Dojo build process



This repository contains all of the custom Webpack plugins and loaders used by @dojo/cli-build-app and @dojo/cli-build-widget to facilitate building Dojo 2 applications and widgets, respectively.
-----
- Usage
- Loaders
- css-module-decorator-loader
- css-module-dts-loader
- promise-loader
- static-build-loader
- Plugins
- build-time-render
- css-module-plugin
- emit-all-plugin
- external-loader-plugin
- i18n-plugin
- service-worker-plugin
- webpack-bundle-analyzer
- bootstrap-plugin
- Transformers
- registry-transformer
- element-transformer
- How do I contribute?
- Code Style
- Testing
- Licensing information
To use @dojo/webpack-contrib in a single project, install the package:
``bash`
npm install @dojo/webpack-contrib
A webpack loader that injects CSS module path information into the generated modules, making it easier for @dojo/widget-core to resolve theme styles. This loader takes no options.
A webpack loader that generates .d.ts files for CSS modules. This is used by both @dojo/cli-build-app and @dojo/cli-build-widget to provide in-widget type checks for CSS classes.
The loader expects the following options:
| Property | Type | Optional | Description |
| -------- | ---- | -------- | ----------- |
| type | 'ts' or 'css' | No | The type of file being processed. If ts, the loader assumes the resource is a TypeScript file and will parse it for CSS module imports. If any CSS modules are found, then the loader generates a d.ts file for each. If css is specified, then the loader assumes the resource is a CSS module and generates the .d.ts file for it. |string
| instanceName | | Yes | An optional instance name for the TypeScript compiler created by the ts-loader. This option is valid only when the type is ts, and ensures the same compiler instance is used across all files. |
Example:
`typescript.d.ts
const webpackConfig = {
loaders: [
// Generate files for all CSS modules imported in TypeScript files beneathsrc/
// the directory.d.ts
{
include: './src/',
test: /\.ts$/,
enforce: 'pre',
loader: '@dojo/webpack-contrib/css-module-dts-loader?type=ts&instanceName=APP_NAME'
},
// Generate files for all CSS modules beneath the src/ directory`
{
include: './src/',
test: /\.m\.css$/,
enforce: 'pre',
loader: '@dojo/webpack-contrib/css-module-dts-loader?type=css'
}
]
};
A webpack loader that returns a promise from require() calls that resolves to the requested resource. It also removes absolute paths from source maps, ensuring consistent builds across environments. It is used by @dojo/cli-build-app for lazily loading bundles.
This loader expects two parameters, one required and one optional:
1. The required promise implementation (e.g., bluebird). If there already exists a global Promise constructor, then global should be specified.
2. An optional chunk name.
Example:
`typescript`
const resourcePromise = require('@dojo/webpack-contrib/promise-loader?global,resource-chunk-name!./path/to/resource');
resourcePromise.then((resource) => {
// resource is available
})
A webpack loader which allows code to be statically optimized for a particular context at bundling time.
This loader acts on JavaScript. Some examples show the TypeScript source, but the loader will only
work if acting on the compiled output.
The loader examines code, looking for usages of @dojo/has, @dojo/has.exists, @dojo/has.add, or _has pragmas_ to _optimize_. It does this by parsing the AST structure of the code, and modifying it when appropriate.
The loader takes three options:
* features: A map of _static_ features or a feature or list of features that resolve to a similar static maptrue
based on the functionality provided by the specified targets. Each key in the map is the name of the feature
and the value is if the feature is present in that context, otherwise false.isRunningInNode
* : An optional boolean parameter. If set to false this indicates that the loader will not bestaticOnly
running in an environment with a Node-like require.
* : A list of feature keys that should _not_ have has.add calls modified. In most cases, this option
will not be needed. It is provided for cases where a module will sometimes be parsed and have its flags resolved statically if so, but
may also not be parsed and may require a different runtime value for the flag.
For example in a webpack configuration, the map of features would look like this:
`js`
{
use: [
{
loader: '@dojo/webpack-contrib/static-build-loader',
options: {
features: {
'foo': true,
'bar': false
},
staticOnly: ['bar']
}
}
]
};foo
This asserts feature is true and feature bar is false.
Alternatively a list of features can be provided that will be resolved to the appropriate map
`js`
{
use: [
{
loader: '@dojo/webpack-contrib/static-build-loader',
options: {
features: [ 'firefox', 'chrome' ]
}
}
]
}
#### Available features
When specifying a static map, any values can be used. When passing a string or list of strings, the following
values are supported. Each value corresponds to the set of known features that the environment supports. If
multiple features are specified, the intersection of available features will be returned.
* android
* chrome
* edge
* firefox
* ie11
* ios
* node
* node8
* safari
In either case, the resulting map is then used in the features below.
#### Dead Code Removal
The loader assumes that the @dojo/has API is being used in modules that are being compiled
into a webpack bundle and attempts to rewrite calls to the has() API when it can see it has a statically asserted flag for
that feature.
The loader detects structures like the following in transpiled TypeScript modules:
`ts
import has from './has';
if (has('foo')) {
console.log('has foo');
}
else {
console.log('doesn\'t have foo');
}
const bar = has('bar') ? 'has bar' : 'doesn\'t have bar';
`
And will rewrite the code (given the static feature set above), like:
`ts
import has from './has';
if (true) {
console.log('has foo');
}
else {
console.log('doesn\'t have foo');
}
const bar = false ? 'has bar' : 'doesn\'t have bar';
`
When this is minified via Uglify via webpack, Uglify looks for structures that can be optimised and would re-write it further to
something like:
`ts
import has from './has';
console.log('has foo');
const bar = 'doesn\'t have bar';
`
Any features which are not statically asserted, are not re-written. This allows the code to determine at run-time if the feature
is present.
#### Elided Imports
The loader looks for _has pragmas_, which are strings that contain a call to has for a specific feature, and
removes the next import found in the code. For example, given the above feature set, which has foo = true andbar = false, the imports of 'a' and 'b' would be removed but 'c' and 'd' would remain.
`tsfoo
"has('foo')";
const statementBeforeImport = 3;
// This is the next import so it will be removed despite
// the conetnet between it and the pragma
import 'a';
// The pragma can be negated to remove the import if the condition
// is known to be false
'!has("bar")';
import 'b';
'!has("foo")';
// This import will not be removed because is not false
import 'c';
'has("baz")';
// This import will not be removed because the value of has('baz')`
// is now known statically
import 'd';
A webpack plugin that generates a bundle's HTML and inlines critical CSS at build time. This is similar to server-side rendering, but does not require a dedicated server to manage it.
The plugin takes an options object with the following properties:
| Property | Type | Optional | Description |
| -------- | ---- | -------- | ----------- |
| entries | string[] | No | The entry scripts to include in the generated HTML file |string[]
| paths | or { path: string; match: string[] } | Yes | An array of paths that will be matched against the URL hash, rendering the HTML associated with any matched path. If the path is a string, then it will be compared directly to window.location.hash. If the path is an object, then it should include a path string that will be used to resolve the HTML, and match string array that represents multiple paths that should trigger the path to be rendered. Defaults to an empty array ('[]'). |string
| root | | Yes | The ID for the root HTML element. If falsy, then no HTML will be generated. Defaults to an emtpy string (''). |boolean
| useManifest | | Yes | Determines whether a manifest file should be used to resolve the entries. Defaults to false. |boolean
| static | | Yes | Removes js and css scripts tags from generated index.html files for truly static sites. Not compatible with hash routing. Defaults to false. |
Beyond the plugin itself, it is also beneficial to include the @dojo/webpack-contrib/build-time-render/hasBuildTimeRender module in the entry config option. This file adds the has('build-item-render') flag that applications can use to determine whether the app has been pre-rendered.
The following example will generate an HTML file containing