dojo/webpack-contrib

Name: webpack-contrib

Owner: Dojo

Description: Plugins and loaders for webpack used with Dojo 2

Created: 2017-10-10 14:51:34.0

Updated: 2018-05-02 14:11:21.0

Pushed: 2018-05-19 16:16:11.0

Homepage: null

Size: 566

Language: TypeScript

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

@dojo/webpack-contrib

Build Status codecov npm version

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

To use @dojo/webpack-contrib in a single project, install the package:

install @dojo/webpack-contrib

Loaders

css-module-decorator-loader

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.

css-module-dts-loader

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. | | instanceName | string | 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:

t webpackConfig = {
loaders: [
    // Generate `.d.ts` files for all CSS modules imported in TypeScript files beneath
    // the `src/` directory
    {
        include: './src/',
        test: /\.ts$/,
        enforce: 'pre',
        loader: '@dojo/webpack-contrib/css-module-dts-loader?type=ts&instanceName=APP_NAME'
    },
    // Generate `.d.ts` 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'
    }
]

promise-loader

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:

t resourcePromise = require('@dojo/webpack-contrib/promise-loader?global,resource-chunk-name!./path/to/resource');
urcePromise.then((resource) => {
// resource is available

static-build-loader

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.

Features

The loader examines code, looking for usages of @dojo/has or has pragmas to optimize. It does this by parsing the AST structure of the code, and modifying it when appropriate.

The loader takes two options:

For example in a webpack configuration, the map of features would look like this:


use: [
    {
        loader: '@dojo/webpack-contrib/static-build-loader',
        options: {
            features: {
                'foo': true,
                'bar': false
            }
        }
    }
]

This asserts feature foo is true and feature bar is false. Alternatively a list of features can be provided that will be resolved to the appropriate map


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.

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:

rt has from './has';

has('foo')) {
console.log('has foo');

 {
console.log('doesn\'t have foo');


t bar = has('bar') ? 'has bar' : 'doesn\'t have bar';

And will rewrite the code (given the static feature set above), like:

rt has from './has';

true) {
console.log('has foo');

 {
console.log('doesn\'t have foo');


t 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:

rt has from './has';

ole.log('has foo');

t 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 and bar = false, the imports of 'a' and 'b' would be removed but 'c' and 'd' would remain.

('foo')";
t statementBeforeImport = 3;
his is the next import so it will be removed despite
he conetnet between it and the pragma
rt 'a';
he pragma can be negated to remove the import if the condition
s known to be false
s("bar")';
rt 'b';
s("foo")';
his import will not be removed because `foo` is not false
rt 'c';

("baz")';
his import will not be removed because the value of `has('baz')`
s now known statically
rt 'd';

Plugins

build-time-render

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 | | paths | string[] 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 ('[]'). | | root | string | Yes | The ID for the root HTML element. If falsy, then no HTML will be generated. Defaults to an emtpy string (''). | | useManifest | boolean | Yes | Determines whether a manifest file should be used to resolve the entries. Defaults to false. |

Usage

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 <script> tags for the specified entries, along with the critical CSS and HTML for the root, #account, and #help paths. Both the #faq and #contact hashes will display the #help HTML.

rt BuildTimeRender from '@dojo/webpack-contrib/build-time-render/BuildTimeRender';

t entry = {
main: {
    '@dojo/webpack-contrib/build-time-render/hasBuildTimeRender',
    './src/main.ts',
    './src/main.css'
}


t webpackConfig = {
entry,
plugins: [
    new BuildTimeRender({
        entries: Object.keys(entry),
        paths: [
            '#account',
            { path: '#help', match: [ 'faq', 'contact' ] }
        ],
        root: 'app',
        useManifest: true
    })
]

css-module-plugin

A webpack plugin that converts .m.css import paths to .m.css.js. This is used in conjunction with the css-module-dts-loader loader to ensure that webpack can probably resolve CSS module paths.

If the requested resource uses a relative path, then its path will be resolved relative to the requesting module. Otherwise, the resource will be loaded from ${basePath}node_modules (see below for the definition of basePath):

ath is relative to the current module
rt * as localCss from './path/to/local-styles.m.css';

mported from node_modules
rt * as externalCss from 'some-mid/styles.m.css';

The plugin constructor accepts a single argument:

| Property | Type | Optional | Description | | ——– | —- | ——– | ———– | | basePath | string | No | The root path from which to resolve CSS modules |

external-loader-plugin

External libraries that cannot be loaded normally via webpack can be included in a webpack build using this plugin.

The plugin takes an options object with the following properties:

| Property | Type | Optional | Description | | ——– | —- | ——– | ———– | | dependencies | ExternalDep[] | No | External dependencies to load. Described in more detail below | | hash | boolean | Yes | Whether to use the build's hash to cache bust injected dependencies | | outputPath | string | Yes | Where to copy dependencies to; defaults to “externals” | | pathPrefix | string | Yes | Used to change the directory where files are placed(e.g. placing files in _build for testing) |

All external dependencies specified in the dependencies options will be placed in ${pathPrefix}/${outputPath}. Each ExternalDep in the dependencies array specifies one external dependency. Each can be a string, indicating a path that should be delegated to the configured loader, or an object with the following properties:

| Property | Type | optional | Description | | ——– | —- | ——– | ———– | | from | string | false | A path relative to node_modules specifying the dependency location to copy into the build application. | | to | string | true | A path that replaces from as the location to copy this dependency to. By default, dependencies will be copied to ${externalsOutputPath}/${to} or ${externalsOutputPath}/${from} if to is not specified. | | name | string | true | Indicates that this path, and any children of this path, should be loaded via the external loader | | inject | string, string[], or boolean | true | This property indicates that this dependency defines, or includes, scripts or stylesheets that should be loaded on the page. If inject is set to true, then the file at the location specified by to or from will be loaded on the page. If this dependency is a folder, then inject can be set to a string or array of strings to define one or more files to inject. Each path in inject should be relative to ${externalsOutputPath}/${to} or ${externalsOutputPath}/${from} depending on whether to was provided. |

i18n-plugin

Rather than manually set locale data within an application's entry point, that data can instead be read from a config and injected in at build time.

The plugin accepts an options object with the following properties:

| Property | Type | Optional | Description | | ——– | —- | ——– | ———– | | cldrPaths | string[] | Yes | An array of paths to CLDR JSON modules that should be included in the build and registered with the i18n ecosystem. If a path begins with a “.“, then it is treated as relative to the current working directory. Otherwise, it is treated as a valid mid. | | defaultLocale | string | No | The default locale. | | supportedLocales | string[] | Yes | An array of supported locales beyond the default. | | target | string | Yes | The entry point into which the i18n module should be injected. Defaults to src/main.ts. |

A custom module is generated from the locale data, injected into the bundle, and then imported into the specified entry point. The user's locale is compared against the default locale and supported locales, and if it is supported is set as the root locale for the application. If the user's locale is not supported, then the default locale is used. For example, the user's locale will be used in the following scenarios:

The user's locale can be represented by the default locale:

The user's locale can be represented by one of the supported locales:

However, in the following scenario the default locale will be used, although it still will be possible to switch between any of the supported locales at run time, since their required data will also be included in the build:

Transformers

registry-transformer

A custom TypeScript transformer that generates registry keys for widgets included in lazily-loaded bundles. This allows widget authors to use the same pattern for authoring widgets regardless of whether they are loaded from a registry or imported directly.

For example, if LazyWidget needs to be split into a separate bundle and this transformer is not applied, then LazyWidget would need to be added to the registry (registry.define('lazy-widget', LazyWidget)), and all calls to w(LazyWidget) would need to be updated to reference its registry key (w<LazyWidget>('lazy-widget')). By using this transformer, LazyWidget would instead be added to the registry at build time, allowing existing code to remain unchanged.

How do I contribute?

We appreciate your interest! Please see the Dojo 2 Meta Repository for the Contributing Guidelines.

Code Style

This repository uses prettier for code styling rules and formatting. A pre-commit hook is installed automatically and configured to run prettier against all staged files as per the configuration in the projects package.json.

An additional npm script to run prettier (with write set to true) against all src and test project files is available by running:

run prettier
Testing

To test this package, after ensuring all dependencies are installed, run the following command:

unt test
Licensing information

© 2018 JS Foundation. New BSD license.


This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.