@atlassian/webresource-webpack-plugin 4.10.2-64a2ef2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +20 -0
- package/.eslintrc +72 -0
- package/.nvmrc +1 -0
- package/.prettierrc +6 -0
- package/CHANGELOG.md +318 -0
- package/CONTRIBUTING.md +92 -0
- package/LICENSE +13 -0
- package/README.md +709 -0
- package/RELEASE.md +17 -0
- package/package.json +118 -0
- package/src/AppResources.js +198 -0
- package/src/QUnitTestResources.js +88 -0
- package/src/WebpackHelpers.js +176 -0
- package/src/WebpackRuntimeHelpers.js +7 -0
- package/src/WrmPlugin.js +676 -0
- package/src/defaults/builtInProvidedDependencies.js +22 -0
- package/src/flattenReduce.js +1 -0
- package/src/helpers/options-parser.js +32 -0
- package/src/helpers/provided-dependencies.js +21 -0
- package/src/helpers/string.js +12 -0
- package/src/helpers/web-resource-entrypoints.js +66 -0
- package/src/helpers/web-resource-generator.js +138 -0
- package/src/helpers/web-resource-parser.js +44 -0
- package/src/helpers/xml.js +44 -0
- package/src/logger.js +28 -0
- package/src/mergeMaps.js +32 -0
- package/src/renderCondition.js +29 -0
- package/src/renderTransformation.js +44 -0
- package/src/settings/base-dependencies.js +42 -0
- package/src/shims/qunit-require-shim.js +19 -0
- package/src/types/typedefs.js +50 -0
- package/src/webpack-modules/EmptyExportsModule.js +26 -0
- package/src/webpack-modules/ProvidedExternalDependencyModule.js +30 -0
- package/src/webpack-modules/WrmDependencyModule.js +12 -0
- package/src/webpack-modules/WrmResourceModule.js +33 -0
- package/test/.eslintrc +11 -0
- package/test/unit/ProvidedExternalDependencyModule.test.js +63 -0
- package/test/unit/WebpackHelpers.test.js +37 -0
- package/test/unit/renderCondition.test.js +240 -0
- package/test/unit/renderTransformation.test.js +69 -0
- package/test/unit/webpack-modules/WrmDependencyModule.test.js +24 -0
- package/test/use-cases/.eslintrc +14 -0
- package/test/use-cases/asset-content-type/asset-content-type.test.js +50 -0
- package/test/use-cases/asset-content-type/src/app.js +8 -0
- package/test/use-cases/asset-content-type/src/ice.png +0 -0
- package/test/use-cases/asset-content-type/src/rect.svg +4 -0
- package/test/use-cases/asset-content-type/webpack.config.js +33 -0
- package/test/use-cases/asset-loading-via-js/asset-loading-via-js.test.js +61 -0
- package/test/use-cases/asset-loading-via-js/src/app.js +8 -0
- package/test/use-cases/asset-loading-via-js/src/ice.png +0 -0
- package/test/use-cases/asset-loading-via-js/src/rect.svg +4 -0
- package/test/use-cases/asset-loading-via-js/webpack.config.js +31 -0
- package/test/use-cases/associations-complex/associations-complex.test.js +82 -0
- package/test/use-cases/associations-complex/package-lock.json +73 -0
- package/test/use-cases/associations-complex/package.json +9 -0
- package/test/use-cases/associations-complex/src/copied-file-should-be-ignored.js +0 -0
- package/test/use-cases/associations-complex/src/entry.js +5 -0
- package/test/use-cases/associations-complex/src/entry2.js +5 -0
- package/test/use-cases/associations-complex/src/qunit.tests.js +2 -0
- package/test/use-cases/associations-complex/src/to-be-chunked.js +1 -0
- package/test/use-cases/associations-complex/webpack.config.js +48 -0
- package/test/use-cases/associations-simple/associations-simple.test.js +65 -0
- package/test/use-cases/associations-simple/package-lock.json +69 -0
- package/test/use-cases/associations-simple/package.json +5 -0
- package/test/use-cases/associations-simple/src/simple.js +3 -0
- package/test/use-cases/associations-simple/webpack.config.js +27 -0
- package/test/use-cases/async-chunks/async-chunks.test.js +113 -0
- package/test/use-cases/async-chunks/src/app.js +9 -0
- package/test/use-cases/async-chunks/src/async-bar.js +4 -0
- package/test/use-cases/async-chunks/src/async-foo.js +2 -0
- package/test/use-cases/async-chunks/webpack.config.js +40 -0
- package/test/use-cases/async-chunks-named-context/async-chunks-named-context.test.js +76 -0
- package/test/use-cases/async-chunks-named-context/src/app.js +9 -0
- package/test/use-cases/async-chunks-named-context/src/app2.js +5 -0
- package/test/use-cases/async-chunks-named-context/src/async-async-async-bar.js +4 -0
- package/test/use-cases/async-chunks-named-context/src/async-async-bar-two.js +1 -0
- package/test/use-cases/async-chunks-named-context/src/async-async-bar.js +6 -0
- package/test/use-cases/async-chunks-named-context/src/async-bar.js +7 -0
- package/test/use-cases/async-chunks-named-context/src/async-foo.js +2 -0
- package/test/use-cases/async-chunks-named-context/webpack.config.js +43 -0
- package/test/use-cases/async-chunks-of-async-chunks/async-chunks-of-async-chunks.test.js +117 -0
- package/test/use-cases/async-chunks-of-async-chunks/src/app.js +9 -0
- package/test/use-cases/async-chunks-of-async-chunks/src/async-async-async-bar.js +4 -0
- package/test/use-cases/async-chunks-of-async-chunks/src/async-async-bar-two.js +1 -0
- package/test/use-cases/async-chunks-of-async-chunks/src/async-async-bar.js +6 -0
- package/test/use-cases/async-chunks-of-async-chunks/src/async-bar.js +7 -0
- package/test/use-cases/async-chunks-of-async-chunks/src/async-foo.js +2 -0
- package/test/use-cases/async-chunks-of-async-chunks/webpack.config.js +43 -0
- package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/async-chunks-of-async-chunks-with-multiple-entrypoints.test.js +156 -0
- package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/app.js +9 -0
- package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/app2.js +5 -0
- package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/async-async-async-bar.js +4 -0
- package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/async-async-bar-two.js +1 -0
- package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/async-async-bar.js +6 -0
- package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/async-bar.js +7 -0
- package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/async-foo.js +2 -0
- package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/webpack.config.js +43 -0
- package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/css-and-assets-distribution-via-mini-css-extract-plugin.test.js +72 -0
- package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/app.js +8 -0
- package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/app2.js +6 -0
- package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/ice.png +0 -0
- package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/ice2.jpg +0 -0
- package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/rect.svg +4 -0
- package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/rect2.svg +4 -0
- package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/styles.css +8 -0
- package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/styles2.css +8 -0
- package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/webpack.config.js +51 -0
- package/test/use-cases/css-and-assets-via-extract-text-plugin/css-and-assets-via-extract-text-plugin.test.js +87 -0
- package/test/use-cases/css-and-assets-via-extract-text-plugin/src/feature-one.css +7 -0
- package/test/use-cases/css-and-assets-via-extract-text-plugin/src/feature-one.js +3 -0
- package/test/use-cases/css-and-assets-via-extract-text-plugin/src/feature-two.css +3 -0
- package/test/use-cases/css-and-assets-via-extract-text-plugin/src/feature-two.js +1 -0
- package/test/use-cases/css-and-assets-via-extract-text-plugin/src/ice.png +0 -0
- package/test/use-cases/css-and-assets-via-extract-text-plugin/webpack.config.js +46 -0
- package/test/use-cases/css-and-assets-via-style-loader/css-and-assets-via-style-loader.test.js +46 -0
- package/test/use-cases/css-and-assets-via-style-loader/src/app.js +6 -0
- package/test/use-cases/css-and-assets-via-style-loader/src/ice.png +0 -0
- package/test/use-cases/css-and-assets-via-style-loader/src/styles.css +7 -0
- package/test/use-cases/css-and-assets-via-style-loader/webpack.config.js +46 -0
- package/test/use-cases/cyclic-dependencies/cyclic.test.js +24 -0
- package/test/use-cases/cyclic-dependencies/src/a.js +3 -0
- package/test/use-cases/cyclic-dependencies/src/b.js +3 -0
- package/test/use-cases/cyclic-dependencies/src/root.js +3 -0
- package/test/use-cases/cyclic-dependencies/webpack.config.js +24 -0
- package/test/use-cases/data-providers/data-providers.test.js +111 -0
- package/test/use-cases/data-providers/src/first.js +2 -0
- package/test/use-cases/data-providers/src/second.js +2 -0
- package/test/use-cases/data-providers/src/third.js +2 -0
- package/test/use-cases/data-providers/webpack.config.js +73 -0
- package/test/use-cases/data-providers/webpack.config.with-map.js +33 -0
- package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/ensure-runtime-overwrite-of-mini-css-extract-plugin.test.js +86 -0
- package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/app.js +5 -0
- package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/app2.js +5 -0
- package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/ice.png +0 -0
- package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/ice2.jpg +0 -0
- package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/rect.svg +4 -0
- package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/rect2.svg +4 -0
- package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/styles.css +8 -0
- package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/styles2.css +8 -0
- package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/webpack.after.config.js +51 -0
- package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/webpack.before.config.js +51 -0
- package/test/use-cases/jsonp-function-name/jsonp-function-name.test.js +37 -0
- package/test/use-cases/jsonp-function-name/src/app.js +1 -0
- package/test/use-cases/jsonp-function-name/src/foo.js +2 -0
- package/test/use-cases/jsonp-function-name/webpack.config.js +35 -0
- package/test/use-cases/jsonp-function-name-default/jsonp-function-name-default.test.js +39 -0
- package/test/use-cases/jsonp-function-name-default/src/app.js +1 -0
- package/test/use-cases/jsonp-function-name-default/src/foo.js +2 -0
- package/test/use-cases/jsonp-function-name-default/webpack.config.js +34 -0
- package/test/use-cases/location-prefix/location-prefix.test.js +29 -0
- package/test/use-cases/location-prefix/src/simple.js +6 -0
- package/test/use-cases/location-prefix/webpack.config.js +25 -0
- package/test/use-cases/provided-module-replacement/provided-module-replacement.test.js +63 -0
- package/test/use-cases/provided-module-replacement/src/app.js +3 -0
- package/test/use-cases/provided-module-replacement/webpack.config.with-map.js +33 -0
- package/test/use-cases/provided-module-replacement/webpack.config.with-object.js +34 -0
- package/test/use-cases/provided-modules-replacement-with-amd-target/provided-modules-replacement-with-amd-target.test.js +62 -0
- package/test/use-cases/provided-modules-replacement-with-amd-target/src/app.js +3 -0
- package/test/use-cases/provided-modules-replacement-with-amd-target/webpack.config.js +41 -0
- package/test/use-cases/qunit-test-wrm-web-resource/qunit-test-wrm-web-resource.test.js +157 -0
- package/test/use-cases/qunit-test-wrm-web-resource/src/app.2.js +6 -0
- package/test/use-cases/qunit-test-wrm-web-resource/src/app.js +8 -0
- package/test/use-cases/qunit-test-wrm-web-resource/src/bar-dep.js +8 -0
- package/test/use-cases/qunit-test-wrm-web-resource/src/bar-dep_test.js +1 -0
- package/test/use-cases/qunit-test-wrm-web-resource/src/foo-async.js +3 -0
- package/test/use-cases/qunit-test-wrm-web-resource/src/foo-dep.js +4 -0
- package/test/use-cases/qunit-test-wrm-web-resource/src/foo-dep_test.js +1 -0
- package/test/use-cases/qunit-test-wrm-web-resource/webpack.config.js +24 -0
- package/test/use-cases/resource-parameters/resource-parameters.test.js +77 -0
- package/test/use-cases/resource-parameters/src/app.js +12 -0
- package/test/use-cases/resource-parameters/src/ice.png +0 -0
- package/test/use-cases/resource-parameters/src/ice2.jpg +0 -0
- package/test/use-cases/resource-parameters/src/rect.svg +4 -0
- package/test/use-cases/resource-parameters/webpack.config.js +62 -0
- package/test/use-cases/resource-parameters/webpack.svg.config.js +30 -0
- package/test/use-cases/simple/simple.test.js +83 -0
- package/test/use-cases/simple/src/simple.js +3 -0
- package/test/use-cases/simple/webpack.config.js +24 -0
- package/test/use-cases/single-runtime-chunk/single-runtime-chunk.test.js +132 -0
- package/test/use-cases/single-runtime-chunk/src/first.js +2 -0
- package/test/use-cases/single-runtime-chunk/src/second.js +2 -0
- package/test/use-cases/single-runtime-chunk/src/shared.js +3 -0
- package/test/use-cases/single-runtime-chunk/src/third.js +2 -0
- package/test/use-cases/single-runtime-chunk/webpack.config.js +33 -0
- package/test/use-cases/specify-asset-dev-hash/specify-asset-dev-hash.test.js +33 -0
- package/test/use-cases/specify-asset-dev-hash/src/feature.js +6 -0
- package/test/use-cases/specify-asset-dev-hash/src/library.js +6 -0
- package/test/use-cases/specify-asset-dev-hash/webpack.config.js +71 -0
- package/test/use-cases/specify-conditions/specify-conditions.test.js +106 -0
- package/test/use-cases/specify-conditions/src/app.js +5 -0
- package/test/use-cases/specify-conditions/webpack.config.js +65 -0
- package/test/use-cases/specify-explicit-context/specify-explicit-context.test.js +89 -0
- package/test/use-cases/specify-explicit-context/src/app.js +5 -0
- package/test/use-cases/specify-explicit-context/webpack.config.js +34 -0
- package/test/use-cases/specify-explicit-context-no-autogenerated/specify-explicit-context-no-autogenerated.test.js +84 -0
- package/test/use-cases/specify-explicit-context-no-autogenerated/src/app.js +5 -0
- package/test/use-cases/specify-explicit-context-no-autogenerated/webpack.config.js +35 -0
- package/test/use-cases/specify-explicit-name/specify-explicit-name.test.js +110 -0
- package/test/use-cases/specify-explicit-name/src/app.js +5 -0
- package/test/use-cases/specify-explicit-name/webpack.config.js +43 -0
- package/test/use-cases/specify-explicit-state/specify-explicit-state.test.js +96 -0
- package/test/use-cases/specify-explicit-state/src/app.js +5 -0
- package/test/use-cases/specify-explicit-state/webpack.config.js +51 -0
- package/test/use-cases/specify-transformation/disable-transformations.test.js +77 -0
- package/test/use-cases/specify-transformation/extend-transformations.test.js +69 -0
- package/test/use-cases/specify-transformation/specify-transformation.test.js +100 -0
- package/test/use-cases/specify-transformation/src/app.js +13 -0
- package/test/use-cases/specify-transformation/src/ice.png +0 -0
- package/test/use-cases/specify-transformation/src/rect.svg +4 -0
- package/test/use-cases/specify-transformation/src/test.html +1 -0
- package/test/use-cases/specify-transformation/src/test.less +1 -0
- package/test/use-cases/specify-transformation/src/test.txt +1 -0
- package/test/use-cases/specify-transformation/webpack.disable-tranformations.config.js +31 -0
- package/test/use-cases/specify-transformation/webpack.extend-tranformations.config.js +34 -0
- package/test/use-cases/specify-transformation/webpack.specify-transformations.config.js +35 -0
- package/test/use-cases/split-chunks/split-chunks.test.js +102 -0
- package/test/use-cases/split-chunks/src/app.js +7 -0
- package/test/use-cases/split-chunks/src/app2.js +7 -0
- package/test/use-cases/split-chunks/src/bar.js +2 -0
- package/test/use-cases/split-chunks/src/foo.js +2 -0
- package/test/use-cases/split-chunks/src/foo2.js +2 -0
- package/test/use-cases/split-chunks/webpack.config.js +42 -0
- package/test/use-cases/split-chunks-with-runtime/split-chunks-with-runtime.test.js +114 -0
- package/test/use-cases/split-chunks-with-runtime/src/app.js +7 -0
- package/test/use-cases/split-chunks-with-runtime/src/app2.js +7 -0
- package/test/use-cases/split-chunks-with-runtime/src/bar.js +2 -0
- package/test/use-cases/split-chunks-with-runtime/src/foo.js +2 -0
- package/test/use-cases/split-chunks-with-runtime/src/foo2.js +2 -0
- package/test/use-cases/split-chunks-with-runtime/webpack.config.js +43 -0
- package/test/use-cases/split-chunks-with-tests/split-chunks-with-tests.test.js +216 -0
- package/test/use-cases/split-chunks-with-tests/src/app.js +7 -0
- package/test/use-cases/split-chunks-with-tests/src/app2.js +7 -0
- package/test/use-cases/split-chunks-with-tests/src/bar.js +2 -0
- package/test/use-cases/split-chunks-with-tests/src/bar_test.js +1 -0
- package/test/use-cases/split-chunks-with-tests/src/foo.js +2 -0
- package/test/use-cases/split-chunks-with-tests/src/foo2.js +2 -0
- package/test/use-cases/split-chunks-with-tests/src/foo_test.js +1 -0
- package/test/use-cases/split-chunks-with-tests/webpack.config.js +43 -0
- package/test/use-cases/standalone/src/standalone-1.js +1 -0
- package/test/use-cases/standalone/src/standalone-2.js +1 -0
- package/test/use-cases/standalone/standalone.test.js +53 -0
- package/test/use-cases/standalone/webpack.config.js +25 -0
- package/test/use-cases/wrm-dependency-loading/src-amd/app.js +7 -0
- package/test/use-cases/wrm-dependency-loading/src-es6/app.js +7 -0
- package/test/use-cases/wrm-dependency-loading/webpack.config.amd.js +22 -0
- package/test/use-cases/wrm-dependency-loading/webpack.config.es6.js +22 -0
- package/test/use-cases/wrm-dependency-loading/wrm-dependency-loading.test.js +60 -0
- package/test/use-cases/wrm-manifest-path/src/a.js +3 -0
- package/test/use-cases/wrm-manifest-path/src/app.js +3 -0
- package/test/use-cases/wrm-manifest-path/src/app2.js +3 -0
- package/test/use-cases/wrm-manifest-path/src/b.js +3 -0
- package/test/use-cases/wrm-manifest-path/webpack.config.js +27 -0
- package/test/use-cases/wrm-manifest-path/wrm-manifest-path.test.js +57 -0
- package/test/use-cases/wrm-resource-loading/src-amd/app.js +6 -0
- package/test/use-cases/wrm-resource-loading/src-es6/app.js +5 -0
- package/test/use-cases/wrm-resource-loading/src-relative/app.js +5 -0
- package/test/use-cases/wrm-resource-loading/webpack.config.amd.js +23 -0
- package/test/use-cases/wrm-resource-loading/webpack.config.es6.js +23 -0
- package/test/use-cases/wrm-resource-loading/webpack.config.relative.js +23 -0
- package/test/use-cases/wrm-resource-loading/wrm-resource-loading.test.js +89 -0
package/src/WrmPlugin.js
ADDED
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
const assert = require('assert');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { createHash } = require('crypto');
|
|
4
|
+
const PrettyData = require('pretty-data').pd;
|
|
5
|
+
const uuidv4Gen = require('uuid/v4');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const mkdirp = require('mkdirp');
|
|
8
|
+
const once = require('lodash/once');
|
|
9
|
+
const urlJoin = require('url-join');
|
|
10
|
+
const unionBy = require('lodash/unionBy');
|
|
11
|
+
const isObject = require('lodash/isObject');
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
createQUnitResourceDescriptors,
|
|
15
|
+
createResourceDescriptors,
|
|
16
|
+
createTestResourceDescriptors,
|
|
17
|
+
} = require('./helpers/web-resource-generator');
|
|
18
|
+
const { toMap, extractPathPrefixForXml } = require('./helpers/options-parser');
|
|
19
|
+
const { buildProvidedDependency } = require('./helpers/provided-dependencies');
|
|
20
|
+
const { addBaseDependency } = require('./settings/base-dependencies');
|
|
21
|
+
|
|
22
|
+
const ProvidedExternalDependencyModule = require('./webpack-modules/ProvidedExternalDependencyModule');
|
|
23
|
+
const WrmDependencyModule = require('./webpack-modules/WrmDependencyModule');
|
|
24
|
+
const WrmResourceModule = require('./webpack-modules/WrmResourceModule');
|
|
25
|
+
const WebpackHelpers = require('./WebpackHelpers');
|
|
26
|
+
const WebpackRuntimeHelpers = require('./WebpackRuntimeHelpers');
|
|
27
|
+
const logger = require('./logger');
|
|
28
|
+
const QUnitTestResources = require('./QUnitTestResources');
|
|
29
|
+
const AppResources = require('./AppResources');
|
|
30
|
+
const flattenReduce = require('./flattenReduce');
|
|
31
|
+
const mergeMaps = require('./mergeMaps');
|
|
32
|
+
|
|
33
|
+
const { builtInProvidedDependencies } = require('./defaults/builtInProvidedDependencies');
|
|
34
|
+
const { existsSync, readFileSync } = require('fs');
|
|
35
|
+
|
|
36
|
+
const defaultResourceParams = new Map().set('svg', [
|
|
37
|
+
{
|
|
38
|
+
name: 'content-type',
|
|
39
|
+
value: 'image/svg+xml',
|
|
40
|
+
},
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
const defaultTransformations = new Map()
|
|
44
|
+
.set('js', ['jsI18n'])
|
|
45
|
+
.set('soy', ['soyTransformer', 'jsI18n'])
|
|
46
|
+
.set('less', ['lessTransformer']);
|
|
47
|
+
|
|
48
|
+
const DEFAULT_DEV_ASSETS_HASH = 'DEV_PSEUDO_HASH';
|
|
49
|
+
|
|
50
|
+
const ASSOCIATIONS_PATH_IN_BUNDLE = './META-INF/fe-manifest-associations';
|
|
51
|
+
|
|
52
|
+
class WrmPlugin {
|
|
53
|
+
static extendTransformations(values) {
|
|
54
|
+
return mergeMaps(defaultTransformations, toMap(values), (val, key, map) => {
|
|
55
|
+
const oldVals = map.get(key);
|
|
56
|
+
const newVals = []
|
|
57
|
+
.concat(oldVals)
|
|
58
|
+
.concat(val)
|
|
59
|
+
.filter(v => !!v);
|
|
60
|
+
return map.set(key, newVals);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* A Webpack plugin that takes the compilation tree and creates <web-resource> XML definitions that mirror the
|
|
66
|
+
* dependency graph.
|
|
67
|
+
*
|
|
68
|
+
* This plugin will:
|
|
69
|
+
*
|
|
70
|
+
* - generate <web-resource> definitions for each entrypoint, along with additional <web-resource> definitions for
|
|
71
|
+
* and appropriate dependencies on all chunks generated during compilation.
|
|
72
|
+
* - Add <dependency> declarations to each generated <web-resource> as appropriate, both for internal and external
|
|
73
|
+
* dependencies in the graph.
|
|
74
|
+
* - Add appropriate metadata to the <web-resource> definition, such as appropriate <context>s,
|
|
75
|
+
* enabled/disabled state, and more.
|
|
76
|
+
*
|
|
77
|
+
* @param {Object} options - options passed to WRMPlugin
|
|
78
|
+
* @param {String} options.pluginKey - The fully qualified plugin key. e.g.: com.atlassian.jira.plugins.my-jira-plugin
|
|
79
|
+
* @param {String} options.xmlDescriptors - Path to the directory where this plugin stores the descriptors about this plugin, used by the WRM to load your frontend code.
|
|
80
|
+
*
|
|
81
|
+
* @param {Map<String, Object>} [options.providedDependencies] - Map of ES6/AMD module identifiers to their related WRM module keys and JavaScript import values (read: webpack external dependency definition). If this module identifier is imported or required somewhere in the compiled code, it will not be bundled, but instead replaced with the specified external dependency placeholder.
|
|
82
|
+
*
|
|
83
|
+
* @param {String} [options.locationPrefix=''] - Specify the sub-directory for all web-resource location values.
|
|
84
|
+
* @param {String} [options.wrmManifestPath] - Path to the WRM manifest file where this plugin stores the mapping of modules to generated web-resources. e.g.: `{"my-entry": "com.example.app:entrypoint-my-entry"}`. Useful if you set { output: { library, libraryTarget } } in your webpack config, to use your build result as provided dependencies for other builds.
|
|
85
|
+
*
|
|
86
|
+
* @param {Object} [options.assetContentTypes] - [DEPRECATED - use {@param options.resourceParamMap} instead] Specific content-types to be used for certain asset types. Will be added as '<param name="content-type"...' to the resource of the asset.
|
|
87
|
+
* @param {Map<String, Object>} [options.conditionMap] - Conditions to be applied to the specified entry-point.
|
|
88
|
+
* @param {Map<String, Array<String>>} [options.contextMap] - One or more "context"s to which an entrypoint will be added. e.g.: `{"my-entry": ["my-plugin-context", "another-context"]}`
|
|
89
|
+
* @param {Map<String, Array<Object>>} [options.resourceParamMap] - Parameters to be added to specific file types.
|
|
90
|
+
* @param {Map<String, Array<String>>} [options.transformationMap] - Transformations to be applied to the specified file-types.
|
|
91
|
+
* @param {Map<String, String>} [options.webresourceKeyMap] - An explicit name for the web-resource generated per entry point. e.g.: `{"my-entry": "legacy-webresource-name"}`.
|
|
92
|
+
* @param {String} [options.devAssetsHash] - Custom hash used in development environment resources name.
|
|
93
|
+
*
|
|
94
|
+
* @param {Boolean} [options.addEntrypointNameAsContext=true] - Guarantees each entrypoint will be given a context matching its name. Use with caution; this can adversely affect page weight and may conflict with other plugins and feature code.
|
|
95
|
+
* @param {Boolean} [options.addAsyncNameAsContext=true] - Adds the name of the async chunk as a context prefixed by `async-chunk-`. Will only do so if a webpackChunkName is set.
|
|
96
|
+
* @param {Boolean} [options.watch=false] - Trigger watch mode - this requires webpack-dev-server and will redirect requests to the entrypoints to the dev-server that must be running under webpack's `options.output.publicPath`.
|
|
97
|
+
* @param {Boolean} [options.watchPrepare=false] - In conjunction with watch mode - indicates that only "redirects" to a webserver should be build in this run.
|
|
98
|
+
* @param {Boolean} [options.standalone=false] - Build standalone web-resources - assumes no transformations, other chunks or base contexts are needed.
|
|
99
|
+
* @param {Boolean} [options.noWRM=false] - Do not add any WRM specifics to the webpack runtime to allow development on a greenfield.
|
|
100
|
+
* @param {Boolean} [options.verbose=false] - Indicate if log output should be verbose.
|
|
101
|
+
*
|
|
102
|
+
* @param {Map<String, DataProvider[]>} [options.dataProvidersMap] - A list of data providers that will be added to the entry point e.g.: `{"my-entry": [{ key: "data-provider-key", class: "my.data.provider.JavaClass" }]}`
|
|
103
|
+
*
|
|
104
|
+
* @constructs
|
|
105
|
+
*/
|
|
106
|
+
constructor(options = {}) {
|
|
107
|
+
assert(
|
|
108
|
+
options.pluginKey,
|
|
109
|
+
`Option [String] "pluginKey" not specified. You must specify a valid fully qualified plugin key. e.g.: com.atlassian.jira.plugins.my-jira-plugin`
|
|
110
|
+
);
|
|
111
|
+
assert(
|
|
112
|
+
options.xmlDescriptors,
|
|
113
|
+
`Option [String] "xmlDescriptors" not specified. You must specify the path to the directory where this plugin stores the descriptors about this plugin, used by the WRM to load your frontend code. This should point somewhere in the "target/classes" directory.`
|
|
114
|
+
);
|
|
115
|
+
assert(path.isAbsolute(options.xmlDescriptors), `Option [String] "xmlDescriptors" must be absolute!`);
|
|
116
|
+
|
|
117
|
+
// pull out our options
|
|
118
|
+
this.options = Object.assign(
|
|
119
|
+
{
|
|
120
|
+
addEntrypointNameAsContext: true,
|
|
121
|
+
addAsyncNameAsContext: true,
|
|
122
|
+
conditionMap: new Map(),
|
|
123
|
+
dataProvidersMap: new Map(),
|
|
124
|
+
contextMap: new Map(),
|
|
125
|
+
webresourceKeyMap: new Map(),
|
|
126
|
+
providedDependencies: new Map(),
|
|
127
|
+
verbose: false,
|
|
128
|
+
resourceParamMap: defaultResourceParams,
|
|
129
|
+
transformationMap: defaultTransformations,
|
|
130
|
+
},
|
|
131
|
+
options
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
logger.setVerbose(this.options.verbose);
|
|
135
|
+
|
|
136
|
+
// convert various maybe-objects to maps
|
|
137
|
+
[
|
|
138
|
+
'providedDependencies',
|
|
139
|
+
'conditionMap',
|
|
140
|
+
'contextMap',
|
|
141
|
+
'resourceParamMap',
|
|
142
|
+
'webresourceKeyMap',
|
|
143
|
+
'dataProvidersMap',
|
|
144
|
+
].forEach(prop => (this.options[prop] = toMap(this.options[prop])));
|
|
145
|
+
|
|
146
|
+
// make sure various maps contain only unique items
|
|
147
|
+
this.options.resourceParamMap = this.ensureResourceParamsAreUnique(this.options.resourceParamMap);
|
|
148
|
+
this.options.transformationMap = this.ensureTransformationsAreUnique(this.options.transformationMap);
|
|
149
|
+
this.options.providedDependencies = this.ensureProvidedDependenciesAreUnique(this.options.providedDependencies);
|
|
150
|
+
this.options.dataProvidersMap = this.ensureDataProvidersMapIsValid(this.options.dataProvidersMap);
|
|
151
|
+
|
|
152
|
+
this.getAssetsUUID = once(this.getAssetsUUID.bind(this));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Generate an asset uuid per build - this is used to ensure we have a new "cache" for our assets per build.
|
|
157
|
+
* As JIRA-Server does not "rebuild" too often, this can be considered reasonable.
|
|
158
|
+
*
|
|
159
|
+
* @param {Boolean} isProduction Is webpack running in production mode
|
|
160
|
+
* @returns {String} Unique hash ID
|
|
161
|
+
*/
|
|
162
|
+
getAssetsUUID(isProduction) {
|
|
163
|
+
return isProduction ? uuidv4Gen() : this.getDevAssetHash();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
getDevAssetHash() {
|
|
167
|
+
return this.options.devAssetsHash ? this.options.devAssetsHash : DEFAULT_DEV_ASSETS_HASH;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
ensureTransformationsAreUnique(transformations) {
|
|
171
|
+
const results = toMap(transformations);
|
|
172
|
+
results.forEach((val, key, map) => {
|
|
173
|
+
const values = [].concat(val).filter(v => !!v);
|
|
174
|
+
map.set(key, Array.from(new Set(values)));
|
|
175
|
+
});
|
|
176
|
+
return results;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
ensureResourceParamsAreUnique(params) {
|
|
180
|
+
const results = toMap(params);
|
|
181
|
+
results.forEach((val, key, map) => {
|
|
182
|
+
const values = [].concat(val).filter(v => !!v);
|
|
183
|
+
map.set(key, unionBy(values.reverse(), 'name').reverse());
|
|
184
|
+
});
|
|
185
|
+
return results;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
ensureProvidedDependenciesAreUnique(providedDependencies) {
|
|
189
|
+
const result = new Map(builtInProvidedDependencies);
|
|
190
|
+
|
|
191
|
+
for (let [name, providedDependency] of providedDependencies) {
|
|
192
|
+
if (result.has(name)) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
result.set(name, providedDependency);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
logger.log('Using provided dependencies', Array.from(result));
|
|
200
|
+
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Filters and validates the data providers option
|
|
206
|
+
*
|
|
207
|
+
* @param {Map<String, DataProvider[]>} dataProvidersMap
|
|
208
|
+
* @return {Map<String, DataProvider[]>}
|
|
209
|
+
*/
|
|
210
|
+
ensureDataProvidersMapIsValid(dataProvidersMap) {
|
|
211
|
+
const map = new Map();
|
|
212
|
+
const requiredKeys = ['key', 'class'];
|
|
213
|
+
|
|
214
|
+
for (const [entryPoint, dataProviders] of dataProvidersMap) {
|
|
215
|
+
if (!Array.isArray(dataProviders)) {
|
|
216
|
+
logger.error(
|
|
217
|
+
`The value of data providers for "${entryPoint}" entry point should be an array of data providers.`,
|
|
218
|
+
{ entryPoint, dataProviders }
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const validDataProviders = [];
|
|
225
|
+
|
|
226
|
+
for (const dataProvider of dataProviders) {
|
|
227
|
+
const keys = isObject ? Object.keys(dataProvider) : [];
|
|
228
|
+
const isValidShape = requiredKeys.every(key => keys.includes(key));
|
|
229
|
+
|
|
230
|
+
if (!isValidShape) {
|
|
231
|
+
logger.error(
|
|
232
|
+
`The data provider shape for "${entryPoint}" entry point doesn't include required keys: ${requiredKeys.concat(
|
|
233
|
+
', '
|
|
234
|
+
)}.`,
|
|
235
|
+
{ entryPoint, dataProvider }
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const { key, class: providerClass } = dataProvider;
|
|
242
|
+
|
|
243
|
+
if (!key || !providerClass) {
|
|
244
|
+
logger.error(
|
|
245
|
+
`The data provider shape for "${entryPoint}" entry point contains missing or empty values.`,
|
|
246
|
+
{
|
|
247
|
+
entryPoint,
|
|
248
|
+
key,
|
|
249
|
+
class: providerClass,
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
validDataProviders.push({
|
|
257
|
+
key,
|
|
258
|
+
class: providerClass,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (validDataProviders.length) {
|
|
263
|
+
map.set(entryPoint, validDataProviders);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return map;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
checkConfig(compiler) {
|
|
271
|
+
const ensurePackageName = () => {
|
|
272
|
+
if (!this.options.packageName) {
|
|
273
|
+
let packageName;
|
|
274
|
+
|
|
275
|
+
// Find package closest to context
|
|
276
|
+
let directory = compiler.context;
|
|
277
|
+
while (directory !== path.parse(directory).root) {
|
|
278
|
+
const packageJsonPath = path.join(directory, 'package.json');
|
|
279
|
+
if (existsSync(packageJsonPath)) {
|
|
280
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
281
|
+
packageName = packageJson.name;
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
directory = path.dirname(directory);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (!packageName) {
|
|
288
|
+
throw new Error('WrmPlugin expects Webpack context to be NPM package.');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
this.options.packageName = packageName;
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
compiler.hooks.afterEnvironment.tap('Check Config', () => {
|
|
296
|
+
const outputOptions = compiler.options.output;
|
|
297
|
+
|
|
298
|
+
// check for the jsonp function option
|
|
299
|
+
const { jsonpFunction } = outputOptions;
|
|
300
|
+
if (!jsonpFunction || jsonpFunction === 'webpackJsonp') {
|
|
301
|
+
const generatedJsonpFunction = `atlassianWebpackJsonp${createHash('md5')
|
|
302
|
+
.update(this.options.pluginKey)
|
|
303
|
+
.digest('hex')}`;
|
|
304
|
+
logger.warn(`
|
|
305
|
+
*********************************************************************************
|
|
306
|
+
The output.jsonpFunction is not specified. This needs to be done to prevent clashes.
|
|
307
|
+
An automated jsonpFunction name for this plugin was created:
|
|
308
|
+
|
|
309
|
+
"${generatedJsonpFunction}"
|
|
310
|
+
*********************************************************************************
|
|
311
|
+
|
|
312
|
+
`);
|
|
313
|
+
outputOptions.jsonpFunction = generatedJsonpFunction;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
ensurePackageName();
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
overwritePublicPath(compiler) {
|
|
321
|
+
const isProductionMode = WebpackHelpers.isRunningInProductionMode(compiler);
|
|
322
|
+
|
|
323
|
+
compiler.hooks.compilation.tap('OverwritePublicPath Compilation', compilation => {
|
|
324
|
+
compilation.mainTemplate.hooks.requireExtensions.tap(
|
|
325
|
+
'OverwritePublicPath Require-Extensions',
|
|
326
|
+
standardScript => {
|
|
327
|
+
// Ensure the `AJS.contextPath` function is available at runtime.
|
|
328
|
+
addBaseDependency('com.atlassian.plugins.atlassian-plugins-webresource-plugin:context-path');
|
|
329
|
+
const uuid = this.getAssetsUUID(isProductionMode);
|
|
330
|
+
|
|
331
|
+
// Add the public path extension to the webpack module runtime.
|
|
332
|
+
return `${standardScript}
|
|
333
|
+
if (typeof AJS !== "undefined") {
|
|
334
|
+
${compilation.mainTemplate.requireFn}.p = AJS.contextPath() + "/s/${uuid}/_/download/resources/${
|
|
335
|
+
this.options.pluginKey
|
|
336
|
+
}:assets-${uuid}/";
|
|
337
|
+
}
|
|
338
|
+
`;
|
|
339
|
+
}
|
|
340
|
+
);
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
hookUpProvidedDependencies(compiler) {
|
|
345
|
+
WebpackRuntimeHelpers.hookIntoNormalModuleFactory(compiler, factory => (data, callback) => {
|
|
346
|
+
const target = compiler.options.output.libraryTarget;
|
|
347
|
+
const request = data.dependencies[0].request;
|
|
348
|
+
// get globally available libraries through wrm
|
|
349
|
+
if (this.options.providedDependencies.has(request)) {
|
|
350
|
+
logger.log('plugging hole into request to %s, will be provided as a dependency through WRM', request);
|
|
351
|
+
const p = this.options.providedDependencies.get(request);
|
|
352
|
+
callback(null, new ProvidedExternalDependencyModule(p.import, p.dependency, target));
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
factory(data, callback);
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
injectWRMSpecificRequestTypes(compiler) {
|
|
360
|
+
WebpackRuntimeHelpers.hookIntoNormalModuleFactory(compiler, factory => (data, callback) => {
|
|
361
|
+
const target = compiler.options.output.libraryTarget;
|
|
362
|
+
const request = data.dependencies[0].request;
|
|
363
|
+
// import web-resources we find static import statements for
|
|
364
|
+
if (request.startsWith('wr-dependency!')) {
|
|
365
|
+
const res = request.substr('wr-dependency!'.length);
|
|
366
|
+
logger.log('adding %s as a web-resource dependency through WRM', res);
|
|
367
|
+
callback(null, new WrmDependencyModule(res, target, this.options.pluginKey));
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// import resources we find static import statements for
|
|
372
|
+
if (request.startsWith('wr-resource!')) {
|
|
373
|
+
const res = request.substr('wr-resource!'.length);
|
|
374
|
+
logger.log('adding %s as a resource through WRM', res);
|
|
375
|
+
|
|
376
|
+
callback(null, new WrmResourceModule(res, target, data.context, compiler.options.context));
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
factory(data, callback);
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
enableAsyncLoadingWithWRM(compiler) {
|
|
385
|
+
compiler.hooks.compilation.tap('enable async loading with wrm - compilation', compilation => {
|
|
386
|
+
// copy & pasted hack from webpack
|
|
387
|
+
if (!compilation.mainTemplate.hooks.jsonpScript) {
|
|
388
|
+
const SyncWaterfallHook = require('tapable').SyncWaterfallHook;
|
|
389
|
+
compilation.mainTemplate.hooks.jsonpScript = new SyncWaterfallHook(['source', 'chunk', 'hash']);
|
|
390
|
+
}
|
|
391
|
+
compilation.mainTemplate.hooks.requireEnsure.tap(
|
|
392
|
+
'enable async loading with wrm - jsonp-script',
|
|
393
|
+
(source, chunk) => {
|
|
394
|
+
// Ensure the WRM.require function is available at runtime.
|
|
395
|
+
// TODO: understand how to set this data on chunk "properly" so that
|
|
396
|
+
// our normalModuleFactory hook will pick it up and generate this dep for us.
|
|
397
|
+
chunk.needsWrmRequire = true;
|
|
398
|
+
|
|
399
|
+
// Add the WRM async loader in to the webpack module runtime.
|
|
400
|
+
return `
|
|
401
|
+
if(installedChunks[chunkId] === 0) { // 0 means "already installed".
|
|
402
|
+
return Promise.resolve();
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (installedChunks[chunkId]) {
|
|
406
|
+
return installedChunks[chunkId][2];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
promises.push(
|
|
410
|
+
new Promise(function(resolve, reject) {
|
|
411
|
+
installedChunks[chunkId] = [resolve, reject];
|
|
412
|
+
}),
|
|
413
|
+
new Promise(function(resolve, reject) {
|
|
414
|
+
WRM.require('wrc!${this.options.pluginKey}:' + chunkId).then(resolve, reject);
|
|
415
|
+
})
|
|
416
|
+
);
|
|
417
|
+
return installedChunks[chunkId][2] = Promise.all(promises);
|
|
418
|
+
`;
|
|
419
|
+
}
|
|
420
|
+
);
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
shouldOverwritePublicPath() {
|
|
425
|
+
if (this.options.watch) {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
if (this.options.standalone) {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
if (this.options.noWRM) {
|
|
432
|
+
return false;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
shouldEnableAsyncLoadingWithWRM() {
|
|
439
|
+
if (this.options.standalone) {
|
|
440
|
+
return false;
|
|
441
|
+
}
|
|
442
|
+
if (this.options.noWRM) {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
apply(compiler) {
|
|
450
|
+
// ensure settings make sense
|
|
451
|
+
this.checkConfig(compiler);
|
|
452
|
+
|
|
453
|
+
// hook up external dependencies
|
|
454
|
+
this.hookUpProvidedDependencies(compiler);
|
|
455
|
+
// allow `wr-dependency/wr-resource` require calls.
|
|
456
|
+
this.injectWRMSpecificRequestTypes(compiler);
|
|
457
|
+
|
|
458
|
+
if (this.shouldOverwritePublicPath()) {
|
|
459
|
+
this.overwritePublicPath(compiler);
|
|
460
|
+
}
|
|
461
|
+
if (this.shouldEnableAsyncLoadingWithWRM()) {
|
|
462
|
+
this.enableAsyncLoadingWithWRM(compiler);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
this.assetNames = new Map();
|
|
466
|
+
|
|
467
|
+
const isProductionMode = WebpackHelpers.isRunningInProductionMode(compiler);
|
|
468
|
+
const assetsUUID = this.getAssetsUUID(isProductionMode);
|
|
469
|
+
|
|
470
|
+
// Generate a 1:1 mapping from original filenames to compiled filenames
|
|
471
|
+
compiler.hooks.compilation.tap('wrm plugin setup phase', compilation => {
|
|
472
|
+
compilation.hooks.normalModuleLoader.tap('wrm plugin - normal module', (loaderContext, module) => {
|
|
473
|
+
const { emitFile } = loaderContext;
|
|
474
|
+
loaderContext.emitFile = (name, content, sourceMap) => {
|
|
475
|
+
const originalName = module.userRequest;
|
|
476
|
+
this.assetNames.set(originalName, name);
|
|
477
|
+
|
|
478
|
+
return emitFile.call(module, name, content, sourceMap);
|
|
479
|
+
};
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
// When the compiler is about to emit files, we jump in to produce our resource descriptors for the WRM.
|
|
484
|
+
compiler.hooks.emit.tapAsync('wrm plugin emit phase', (compilation, callback) => {
|
|
485
|
+
const pathPrefix = extractPathPrefixForXml(this.options.locationPrefix);
|
|
486
|
+
const appResourceGenerator = new AppResources(
|
|
487
|
+
assetsUUID,
|
|
488
|
+
this.assetNames,
|
|
489
|
+
this.options,
|
|
490
|
+
compiler,
|
|
491
|
+
compilation
|
|
492
|
+
);
|
|
493
|
+
const testResourcesGenerator = new QUnitTestResources(assetsUUID, this.options, compiler, compilation);
|
|
494
|
+
|
|
495
|
+
const webResources = [];
|
|
496
|
+
const entryPointsResourceDescriptors = appResourceGenerator.getEntryPointsResourceDescriptors();
|
|
497
|
+
const resourceParamMap = this.options.resourceParamMap;
|
|
498
|
+
|
|
499
|
+
// `assetContentTypes` is DEPRECATED. This code block ensures we're backwards compatible, by applying the
|
|
500
|
+
// specified `assetContentTypes` into the `resourceParamMap`.
|
|
501
|
+
// This should be removed once we get rid of `assetContentTypes` once and for all.
|
|
502
|
+
if (this.options.assetContentTypes) {
|
|
503
|
+
logger.warn(
|
|
504
|
+
`Option 'assetContentTypes' is deprecated and will be removed in a future version. Use 'resourceParamMap' instead. See README for further instructions.`
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
Object.keys(this.options.assetContentTypes).forEach(fileExtension => {
|
|
508
|
+
const contentType = this.options.assetContentTypes[fileExtension];
|
|
509
|
+
|
|
510
|
+
if (!resourceParamMap.has(fileExtension)) {
|
|
511
|
+
resourceParamMap.set(fileExtension, []);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const params = resourceParamMap.get(fileExtension);
|
|
515
|
+
|
|
516
|
+
if (params.find(param => param.name === 'content-type')) {
|
|
517
|
+
logger.warn(
|
|
518
|
+
`There's already a 'content-type' defined for '${fileExtension}' in 'resourceParamMap'. Please stop using 'assetContentTypes'`
|
|
519
|
+
);
|
|
520
|
+
} else {
|
|
521
|
+
params.push({ name: 'content-type', value: contentType });
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
const resourceDescriptors = createResourceDescriptors(
|
|
527
|
+
this.options.standalone
|
|
528
|
+
? entryPointsResourceDescriptors
|
|
529
|
+
: appResourceGenerator.getResourceDescriptors(),
|
|
530
|
+
this.options.transformationMap,
|
|
531
|
+
pathPrefix,
|
|
532
|
+
resourceParamMap,
|
|
533
|
+
this.options.standalone
|
|
534
|
+
);
|
|
535
|
+
webResources.push(resourceDescriptors);
|
|
536
|
+
|
|
537
|
+
if (this.options.__testGlobs__ && !this.options.watch) {
|
|
538
|
+
testResourcesGenerator.injectQUnitShim();
|
|
539
|
+
const testResourceDescriptors = createTestResourceDescriptors(
|
|
540
|
+
testResourcesGenerator.createAllFileTestWebResources(),
|
|
541
|
+
this.options.transformationMap
|
|
542
|
+
);
|
|
543
|
+
const qUnitTestResourceDescriptors = createQUnitResourceDescriptors(
|
|
544
|
+
testResourcesGenerator.getTestFiles()
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
webResources.push(testResourceDescriptors, qUnitTestResourceDescriptors);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
const outputPath = compiler.options.output.path;
|
|
551
|
+
|
|
552
|
+
const xmlDescriptors = PrettyData.xml(`<bundles>${webResources.join('')}</bundles>`);
|
|
553
|
+
const xmlDescriptorWebpackPath = path.relative(outputPath, this.options.xmlDescriptors);
|
|
554
|
+
|
|
555
|
+
compilation.assets[xmlDescriptorWebpackPath] = {
|
|
556
|
+
source: () => new Buffer(xmlDescriptors),
|
|
557
|
+
size: () => Buffer.byteLength(xmlDescriptors),
|
|
558
|
+
};
|
|
559
|
+
|
|
560
|
+
if (this.options.wrmManifestPath) {
|
|
561
|
+
const { library, libraryTarget } = compiler.options.output;
|
|
562
|
+
if (!library || !libraryTarget) {
|
|
563
|
+
logger.error(
|
|
564
|
+
'Can only use wrmManifestPath in conjunction with output.library and output.libraryTarget'
|
|
565
|
+
);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
if (libraryTarget !== 'amd') {
|
|
570
|
+
logger.error(
|
|
571
|
+
`Could not create manifest mapping. LibraryTarget '${libraryTarget}' is not supported. Use 'amd'`
|
|
572
|
+
);
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const wrmManifestMapping = entryPointsResourceDescriptors
|
|
577
|
+
.filter(({ attributes }) => attributes.moduleId)
|
|
578
|
+
.reduce((result, { attributes: { key: resourceKey, moduleId } }) => {
|
|
579
|
+
const libraryName = compilation.mainTemplate.getAssetPath(compiler.options.output.library, {
|
|
580
|
+
chunk: { name: moduleId },
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
result[moduleId] = buildProvidedDependency(
|
|
584
|
+
this.options.pluginKey,
|
|
585
|
+
resourceKey,
|
|
586
|
+
`require('${libraryName}')`,
|
|
587
|
+
libraryName
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
return result;
|
|
591
|
+
}, {});
|
|
592
|
+
const wrmManifestJSON = JSON.stringify({ providedDependencies: wrmManifestMapping }, null, 4);
|
|
593
|
+
const wrmManifestWebpackPath = path.relative(outputPath, this.options.wrmManifestPath);
|
|
594
|
+
|
|
595
|
+
compilation.assets[wrmManifestWebpackPath] = {
|
|
596
|
+
source: () => new Buffer(wrmManifestJSON),
|
|
597
|
+
size: () => Buffer.byteLength(wrmManifestJSON),
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// generate association report in case packageName is provided
|
|
602
|
+
if (this.options.packageName) {
|
|
603
|
+
const descriptors = appResourceGenerator.getResourceDescriptors();
|
|
604
|
+
|
|
605
|
+
const files = [...new Set(descriptors.map(descriptor => descriptor.resources).flat()).values()];
|
|
606
|
+
|
|
607
|
+
if (this.options.__testGlobs__) {
|
|
608
|
+
files.push(testResourcesGenerator.qunitRequireMockPath);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
const output = {
|
|
612
|
+
packageName: this.options.packageName,
|
|
613
|
+
outputDirectoryFiles: files.filter(file => file !== xmlDescriptorWebpackPath),
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
const jsonOutput = JSON.stringify(output, null, 2);
|
|
617
|
+
|
|
618
|
+
const outputDir = path.join(compiler.outputPath, ASSOCIATIONS_PATH_IN_BUNDLE);
|
|
619
|
+
const outputFile = path.join(outputDir, `${this.options.pluginKey}-webpack.intermediary.json`);
|
|
620
|
+
|
|
621
|
+
if (!fs.existsSync(outputDir)) {
|
|
622
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
fs.writeFileSync(outputFile, jsonOutput);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
if (this.options.watch && this.options.watchPrepare) {
|
|
629
|
+
const entrypointDescriptors = appResourceGenerator.getResourceDescriptors();
|
|
630
|
+
const redirectDescriptors = entrypointDescriptors
|
|
631
|
+
.map(c => c.resources)
|
|
632
|
+
.reduce(flattenReduce, [])
|
|
633
|
+
.filter(res => path.extname(res) === '.js')
|
|
634
|
+
.map(r => ({ fileName: r, writePath: path.join(outputPath, r) }));
|
|
635
|
+
|
|
636
|
+
compiler.hooks.done.tap('add watch mode modules', () => {
|
|
637
|
+
mkdirp.sync(path.dirname(this.options.xmlDescriptors));
|
|
638
|
+
fs.writeFileSync(this.options.xmlDescriptors, xmlDescriptors, 'utf8');
|
|
639
|
+
|
|
640
|
+
const generateAssetCall = file => {
|
|
641
|
+
const pathName = urlJoin(compiler.options.output.publicPath, file);
|
|
642
|
+
|
|
643
|
+
const appendScript = `
|
|
644
|
+
var script = document.createElement('script');
|
|
645
|
+
script.src = '${pathName}';
|
|
646
|
+
script.async = false;
|
|
647
|
+
script.crossOrigin = 'anonymous';
|
|
648
|
+
document.head.appendChild(script);`.trim();
|
|
649
|
+
|
|
650
|
+
if (this.options.useDocumentWriteInWatchMode) {
|
|
651
|
+
return `
|
|
652
|
+
!function(){
|
|
653
|
+
if (document.readyState === "loading") {
|
|
654
|
+
document.write('<script src="${pathName}"></script>')
|
|
655
|
+
} else {
|
|
656
|
+
${appendScript}
|
|
657
|
+
}
|
|
658
|
+
}();
|
|
659
|
+
`;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
return `!function() { ${appendScript} }();`;
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
for (const { fileName, writePath } of redirectDescriptors) {
|
|
666
|
+
fs.writeFileSync(writePath, generateAssetCall(fileName), 'utf8');
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
callback();
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
module.exports = WrmPlugin;
|