Skip to content

Commit ca9091d

Browse files
author
Chuck Dumont
authored
Merge pull request #81 from chuckdumont/work
Support dojo-config-api=0 for building a smaller embedded loader
2 parents b9e5060 + ef998f6 commit ca9091d

28 files changed

+587
-375
lines changed

README.md

+13-5
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ See the [Release Notes](#release-notes) for important information about upgradin
3333

3434
**dojo-webpack-plugin** uses the Dojo loader (dojo.js) at build time to resolve modules based on the properties specified in the Dojo loader config. In addition, a stripped-down build of the loader, as well as the loader config, are embedded in the packed application to support client-side execution of `require()` calls that have not been transformed by Webpack at build time (i.e. `require()` calls that reference non-stactic variables), as well as Dojo's `require.toAbsMid()` and `require.toUrl()` functions.
3535

36-
This package does not include the Dojo loader. A custom build of the Dojo loader is built by Webpack based on the location of Dojo specified in the Dojo loader config. Alternatively, the location of a previously built loader may be specified using the [loader](#loader) option. See [Building the Dojo loader](#building-the-dojo-loader).
36+
This package does not include the Dojo loader. A custom build of the Dojo loader is built by Webpack based on the location of Dojo specified in the Dojo loader config. Alternatively, the location of a previously built loader may be specified using the [loader](#loader) option. See [Building the Dojo loader](#building-the-dojo-loader).
3737

3838
### CommonJS require vs. Dojo synchronous require
3939

@@ -48,7 +48,7 @@ define([], function() {
4848
});
4949
```
5050

51-
If CommonJS `require` calls are being injected into your module by third-party code (e.g. by [ProvidePlugin](https://webpack.js.org/plugins/provide-plugin/)), then you can use the [cjsRequirePatterns](#cjsrequirepatterns) option to specify regular expression patterns to match against module names that should be loaded using CommonJS `require`.
51+
If CommonJS `require` calls are being injected into your module by third-party code (e.g. by [ProvidePlugin](https://webpack.js.org/plugins/provide-plugin/)), then you can use the [cjsRequirePatterns](#cjsrequirepatterns) option to specify regular expression patterns to match against module names that should be loaded using CommonJS `require`.
5252

5353
# The Dojo loader config
5454

@@ -67,12 +67,14 @@ plugins: [
6767
]
6868
```
6969

70-
The loader config may be specified as an object, a function that returns the config object, or as a string which represents the name of a CommonJS module that exports the config (object or function). If specified as an object or a function, then the config expressions are evaluated at build time and the config is exported to the client as a JSON object that is mixed with the `window.dojoConfig` property at application load time.
70+
The loader config may be specified as an object, a function that returns the config object, or as a string which represents the name of a CommonJS module that exports the config (object or function). If specified as an object or a function, then the config expressions are evaluated at build time and the config object is serialized to the client and mixed with the `window.dojoConfig` property at application load time.
7171

7272
If the config is specified as a module name, then the config module will be evaluated both at build time (for the purpose of resolving modules for webpack), and then again at application run time when the config module is loaded on the client. Note that if you want webpack to process the config module (i.e. perform build time variable substitution, etc.) then you must specify the config as a module name.
7373

7474
If you want the config to specify different properties at build time vs. run time, then specify the config as a function that returns the config object and use the [environment](#environment) and [buildEnvironment](#buildenvironment) options so set the properties who's values change depending on the target environment. This works both when the config is evaluated at build time (specified as a function) and when the config is evaluated at build time and runtime (specified as the name of a CommonJS module that exports a function).
7575

76+
There is a small size benefit (~0.5KB after uglify and gzip) to specifying the loader config as an object or function vs. as a module name, because the embedded Dojo loader can be built without the code needed for parsing the Dojo loader config. When using an embedded Dojo loader that does not include the config api, post-processed config objects generated at build time are serialized to the application and used to initialize the embedded loader at application run-time. This plugin will automatically build the embedded Dojo loader with, or without, the config api depending on the value type of the [loaderConfig](#loaderconfig) option, unless the loader config specifies a value for the `dojo-config-api` feature in the `has` property (in which case the embedded Dojo loader is built using the specified value for the feature), or unless you specify a previously built loader using the [loader](#loader) option. See [Overriding profile features](#overriding-profile-features) for details on how to build the loader without the config api. Note that the plugin is able to detect at application build time whether or not the embedded Dojo loader has the config API and can work with either one, with the caveat that the config api is required if the loader config is specified as a module name.
77+
7678
See [js/loaderConfig.js](https://github.com/OpenNTF/dojo-webpack-plugin-sample/blob/master/js/loaderConfig.js) in the sample project for an example of a Dojo loader config that uses the [environment](#environment) and [buildEnvironment](#buildenvironment) options to specify different config paths for build time vs run time. The config also supports running the sample app as a non-packed application with Dojo loaded from a CDN.
7779

7880
# Dojo loader extensions
@@ -222,9 +224,9 @@ This property is optional. If the value is truthy, then console output from bui
222224

223225
# Building the Dojo loader
224226

225-
This plugin uses a custom build of the Dojo loader. The built loader is packaged as a CommonJS module so that it may be more easily consumed by Webpack. The loader build config specifies has.js features which exclude unneeded code (e.g. for loading modules) so that the loader embedded into the client is as small as possible (~4KB after uglify and gzip). The Dojo loader builder requires that the Dojo util directory is a sibling of the `dojo` directory and is named either `util` or `dojo-util`.
227+
This plugin embeds a custom build of the Dojo loader (dojo.js) in your packed application. The built loader is packaged as a CommonJS module so that it may be more easily consumed by Webpack. The loader build profile specifies has.js features which exclude unneeded code (e.g. for loading modules) so that the loader embedded into the client is as small as possible (less than 4KB after uglify and gzip). The Dojo loader builder requires that the Dojo util directory is a sibling of the `dojo` directory and is named either `util` or `dojo-util`.
226228

227-
If you do not want to build the Dojo loader every time Webpack is run, then you can build it manually and specify the location of the built loader using the `loader` option. You can produce a manual build of the loader by running the build script in the buildDojo directory.
229+
If you do not want to build the Dojo loader every time Webpack is run, then you can build it manually and specify the location of the built loader using the [loader](#loader) option. You can produce a manual build of the loader by running the build script in the buildDojo directory.
228230

229231
node node_modules/dojo-webpack-plugin/buildDojo/build.js node_modules/dojo/dojo.js ./release
230232

@@ -243,6 +245,12 @@ plugins: [
243245
]
244246
```
245247

248+
#### Overriding profile features
249+
250+
By default, the embedded loader is built using the static has features defined [here](https://github.com/OpenNTF/dojo-webpack-plugin/blob/master/buildDojo/loaderDefaultFeatures.js). You may override these features by providing an optional, third argument to the build script which specifies the features you want to override as a JSON string. For example, if you specify the [loaderConfig](#loaderconfig) option as an object, or a function that returns an object (as opposed to specifying it as a module name), then you can make the embedded loader smaller by omitting the config api. This would be done as follows:
251+
252+
node node_modules/dojo-webpack-plugin/buildDojo/build.js node_modules/dojo/dojo.js ./release {\"dojo-config-api\":false}
253+
246254
# ES6 Promise dependency in Webpack 2.x
247255

248256
Webpack 2.x includes code in your packed application that uses ES6 Promise. If you need to support browsers that lack ES6 Promise support (e.g. IE 11), then you will need to provide this capability in your application. This plugin provides a tiny wrapper module named [dojoES6Promise](https://github.com/OpenNTF/dojo-webpack-plugin/blob/master/amd/dojoES6Promise.js) that implements ES6 Promise using dojo/Deferred. All you need to do is include this module as an AMD dependency in your application. See [bootstrap.js](https://github.com/OpenNTF/dojo-webpack-plugin-sample/blob/master/js/bootstrap.js) in the sample application for an example.

buildDojo/build.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const fork = require("child_process").fork;
1818

1919
const dojoPath = global.process.argv.length > 2 && global.process.argv[2];
2020
const releaseDir = global.process.argv.length > 3 && global.process.argv[3];
21+
const featureOverrides = global.process.argv.length > 4 && global.process.argv[4] || "{}";
2122
if (!dojoPath) {
2223
throw Error("Path to dojo not specified");
2324
}
@@ -34,7 +35,9 @@ const ls = fork(
3435
path.join(__dirname, "loader.profile.js"),
3536
"--release",
3637
"--releaseDir",
37-
path.resolve(releaseDir)
38+
path.resolve(releaseDir),
39+
"--has",
40+
featureOverrides
3841
]
3942
);
4043

buildDojo/loader.profile.js

+22-37
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ const nodeRequire = require.rawConfig && require.rawConfig.loaderPatch.nodeRequi
2020
const path = nodeRequire("path");
2121
const fs = nodeRequire("fs");
2222

23-
var profilePath, dojoPath;
23+
var profilePath, dojoPath, featureOverrides = {};
2424
process.argv.forEach((arg, i) => {
2525
if (arg === '--profile') {
2626
profilePath = process.argv[i+1];
2727
} else if (arg === '--dojoPath') {
2828
dojoPath = process.argv[i+1];
29+
} else if (arg === '--has') {
30+
featureOverrides = JSON.parse(process.argv[i+1]);
2931
}
3032
});
3133
if (!profilePath) {
@@ -35,17 +37,24 @@ if (!dojoPath) {
3537
throw new Error("--dojoPath command line option not specified");
3638
}
3739

38-
const version = nodeRequire(path.resolve(dojoPath, "../", "./package.json")).version;
39-
const versionParts = version.split(".");
40-
const majorVersion = parseInt(versionParts[0]), minorVersion = parseInt(versionParts[1]), patchVersion = parseInt(versionParts[2]);
41-
if (majorVersion !== 1) {
42-
throw new Error("Unsupported Dojo Version");
40+
function getLoaderDefaultFeatures() {
41+
const version = nodeRequire(path.resolve(dojoPath, "../", "./package.json")).version;
42+
const versionParts = version.split(".");
43+
const majorVersion = parseInt(versionParts[0]), minorVersion = parseInt(versionParts[1]), patchVersion = parseInt(versionParts[2]);
44+
if (majorVersion !== 1) {
45+
throw new Error("Unsupported Dojo Version");
46+
}
47+
const hasInjectApiFix = /* True if the version of Dojo has https://github.com/dojo/dojo/pull/266 */
48+
minorVersion > 12 ||
49+
minorVersion === 12 && patchVersion >= 3 ||
50+
minorVersion === 11 && patchVersion >= 5 ||
51+
minorVersion === 10 && patchVersion >= 9;
52+
53+
var features = nodeRequire(path.join(process.argv[1], "../loaderDefaultFeatures"));
54+
features = Object.assign({}, features, featureOverrides);
55+
features['dojo-inject-api'] = !hasInjectApiFix;
56+
return features;
4357
}
44-
const hasInjectApiFix = /* True if the version of Dojo has https://github.com/dojo/dojo/pull/266 */
45-
minorVersion > 12 ||
46-
minorVersion === 12 && patchVersion >= 3 ||
47-
minorVersion === 11 && patchVersion >= 5 ||
48-
minorVersion === 10 && patchVersion >= 9;
4958

5059
var profile = (() => {
5160
const profileDir = path.resolve(profilePath);
@@ -54,6 +63,7 @@ var profile = (() => {
5463
if (!fs.existsSync(path.resolve(dojoDir, util))) {
5564
util = "../util";
5665
}
66+
5767
return {
5868
layerOptimize: false,
5969
releaseDir: "./release",
@@ -72,32 +82,7 @@ var profile = (() => {
7282
trees: [[".", ".", /\.*/]]
7383
}],
7484

75-
staticHasFeatures:{
76-
'dojo-config-api': 1,
77-
'dojo-inject-api': hasInjectApiFix ? 0 : 1,
78-
'csp-restrictions': 1,
79-
'dojo-built': 1,
80-
'config-dojo-loader-catches': 0,
81-
'config-tlmSiblingOfDojo': 0,
82-
'dojo-log-api': 0,
83-
'dojo-publish-privates': 0,
84-
'dojo-sync-loader': 0,
85-
'dojo-timeout-api': 0,
86-
'dojo-trace-api': 0,
87-
'dojo-sniff': 0,
88-
'dojo-test-sniff': 0,
89-
'dojo-cdn': 0,
90-
'dojo-loader-eval-hint-url': 0,
91-
'config-stripStrict': 0,
92-
'ie-event-behavior': 0,
93-
'dom': 0,
94-
'host-node': 0,
95-
'host-rhino': 0,
96-
'host-webworker': 0,
97-
'dojo-force-activex-xhr': 0,
98-
'dojo-enforceDefine': 0,
99-
'dojo-combo-api': 0
100-
},
85+
staticHasFeatures: getLoaderDefaultFeatures(),
10186

10287
layers: {
10388
"dojo/dojo": {

buildDojo/loaderDefaultFeatures.js

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* (C) Copyright IBM Corp. 2012, 2016 All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
module.exports = {
18+
'dojo-config-api': 1,
19+
'csp-restrictions': 1,
20+
'dojo-built': 1,
21+
/*'dojo-inject-api': 0,*/ // Set in loader.profile.js based on Dojo version
22+
'config-dojo-loader-catches': 0,
23+
'config-tlmSiblingOfDojo': 0,
24+
'dojo-log-api': 0,
25+
'dojo-publish-privates': 0,
26+
'dojo-sync-loader': 0,
27+
'dojo-timeout-api': 0,
28+
'dojo-trace-api': 0,
29+
'dojo-sniff': 0,
30+
'dojo-test-sniff': 0,
31+
'dojo-cdn': 0,
32+
'dojo-loader-eval-hint-url': 0,
33+
'config-stripStrict': 0,
34+
'ie-event-behavior': 0,
35+
'dom': 0,
36+
'host-node': 0,
37+
'host-rhino': 0,
38+
'host-webworker': 0,
39+
'dojo-force-activex-xhr': 0,
40+
'dojo-enforceDefine': 0,
41+
'dojo-combo-api': 0
42+
};

0 commit comments

Comments
 (0)