@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.
Files changed (260) hide show
  1. package/.eslintignore +20 -0
  2. package/.eslintrc +72 -0
  3. package/.nvmrc +1 -0
  4. package/.prettierrc +6 -0
  5. package/CHANGELOG.md +318 -0
  6. package/CONTRIBUTING.md +92 -0
  7. package/LICENSE +13 -0
  8. package/README.md +709 -0
  9. package/RELEASE.md +17 -0
  10. package/package.json +118 -0
  11. package/src/AppResources.js +198 -0
  12. package/src/QUnitTestResources.js +88 -0
  13. package/src/WebpackHelpers.js +176 -0
  14. package/src/WebpackRuntimeHelpers.js +7 -0
  15. package/src/WrmPlugin.js +676 -0
  16. package/src/defaults/builtInProvidedDependencies.js +22 -0
  17. package/src/flattenReduce.js +1 -0
  18. package/src/helpers/options-parser.js +32 -0
  19. package/src/helpers/provided-dependencies.js +21 -0
  20. package/src/helpers/string.js +12 -0
  21. package/src/helpers/web-resource-entrypoints.js +66 -0
  22. package/src/helpers/web-resource-generator.js +138 -0
  23. package/src/helpers/web-resource-parser.js +44 -0
  24. package/src/helpers/xml.js +44 -0
  25. package/src/logger.js +28 -0
  26. package/src/mergeMaps.js +32 -0
  27. package/src/renderCondition.js +29 -0
  28. package/src/renderTransformation.js +44 -0
  29. package/src/settings/base-dependencies.js +42 -0
  30. package/src/shims/qunit-require-shim.js +19 -0
  31. package/src/types/typedefs.js +50 -0
  32. package/src/webpack-modules/EmptyExportsModule.js +26 -0
  33. package/src/webpack-modules/ProvidedExternalDependencyModule.js +30 -0
  34. package/src/webpack-modules/WrmDependencyModule.js +12 -0
  35. package/src/webpack-modules/WrmResourceModule.js +33 -0
  36. package/test/.eslintrc +11 -0
  37. package/test/unit/ProvidedExternalDependencyModule.test.js +63 -0
  38. package/test/unit/WebpackHelpers.test.js +37 -0
  39. package/test/unit/renderCondition.test.js +240 -0
  40. package/test/unit/renderTransformation.test.js +69 -0
  41. package/test/unit/webpack-modules/WrmDependencyModule.test.js +24 -0
  42. package/test/use-cases/.eslintrc +14 -0
  43. package/test/use-cases/asset-content-type/asset-content-type.test.js +50 -0
  44. package/test/use-cases/asset-content-type/src/app.js +8 -0
  45. package/test/use-cases/asset-content-type/src/ice.png +0 -0
  46. package/test/use-cases/asset-content-type/src/rect.svg +4 -0
  47. package/test/use-cases/asset-content-type/webpack.config.js +33 -0
  48. package/test/use-cases/asset-loading-via-js/asset-loading-via-js.test.js +61 -0
  49. package/test/use-cases/asset-loading-via-js/src/app.js +8 -0
  50. package/test/use-cases/asset-loading-via-js/src/ice.png +0 -0
  51. package/test/use-cases/asset-loading-via-js/src/rect.svg +4 -0
  52. package/test/use-cases/asset-loading-via-js/webpack.config.js +31 -0
  53. package/test/use-cases/associations-complex/associations-complex.test.js +82 -0
  54. package/test/use-cases/associations-complex/package-lock.json +73 -0
  55. package/test/use-cases/associations-complex/package.json +9 -0
  56. package/test/use-cases/associations-complex/src/copied-file-should-be-ignored.js +0 -0
  57. package/test/use-cases/associations-complex/src/entry.js +5 -0
  58. package/test/use-cases/associations-complex/src/entry2.js +5 -0
  59. package/test/use-cases/associations-complex/src/qunit.tests.js +2 -0
  60. package/test/use-cases/associations-complex/src/to-be-chunked.js +1 -0
  61. package/test/use-cases/associations-complex/webpack.config.js +48 -0
  62. package/test/use-cases/associations-simple/associations-simple.test.js +65 -0
  63. package/test/use-cases/associations-simple/package-lock.json +69 -0
  64. package/test/use-cases/associations-simple/package.json +5 -0
  65. package/test/use-cases/associations-simple/src/simple.js +3 -0
  66. package/test/use-cases/associations-simple/webpack.config.js +27 -0
  67. package/test/use-cases/async-chunks/async-chunks.test.js +113 -0
  68. package/test/use-cases/async-chunks/src/app.js +9 -0
  69. package/test/use-cases/async-chunks/src/async-bar.js +4 -0
  70. package/test/use-cases/async-chunks/src/async-foo.js +2 -0
  71. package/test/use-cases/async-chunks/webpack.config.js +40 -0
  72. package/test/use-cases/async-chunks-named-context/async-chunks-named-context.test.js +76 -0
  73. package/test/use-cases/async-chunks-named-context/src/app.js +9 -0
  74. package/test/use-cases/async-chunks-named-context/src/app2.js +5 -0
  75. package/test/use-cases/async-chunks-named-context/src/async-async-async-bar.js +4 -0
  76. package/test/use-cases/async-chunks-named-context/src/async-async-bar-two.js +1 -0
  77. package/test/use-cases/async-chunks-named-context/src/async-async-bar.js +6 -0
  78. package/test/use-cases/async-chunks-named-context/src/async-bar.js +7 -0
  79. package/test/use-cases/async-chunks-named-context/src/async-foo.js +2 -0
  80. package/test/use-cases/async-chunks-named-context/webpack.config.js +43 -0
  81. package/test/use-cases/async-chunks-of-async-chunks/async-chunks-of-async-chunks.test.js +117 -0
  82. package/test/use-cases/async-chunks-of-async-chunks/src/app.js +9 -0
  83. package/test/use-cases/async-chunks-of-async-chunks/src/async-async-async-bar.js +4 -0
  84. package/test/use-cases/async-chunks-of-async-chunks/src/async-async-bar-two.js +1 -0
  85. package/test/use-cases/async-chunks-of-async-chunks/src/async-async-bar.js +6 -0
  86. package/test/use-cases/async-chunks-of-async-chunks/src/async-bar.js +7 -0
  87. package/test/use-cases/async-chunks-of-async-chunks/src/async-foo.js +2 -0
  88. package/test/use-cases/async-chunks-of-async-chunks/webpack.config.js +43 -0
  89. package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/async-chunks-of-async-chunks-with-multiple-entrypoints.test.js +156 -0
  90. package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/app.js +9 -0
  91. package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/app2.js +5 -0
  92. package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/async-async-async-bar.js +4 -0
  93. package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/async-async-bar-two.js +1 -0
  94. package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/async-async-bar.js +6 -0
  95. package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/async-bar.js +7 -0
  96. package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/src/async-foo.js +2 -0
  97. package/test/use-cases/async-chunks-of-async-chunks-with-multiple-entrypoints/webpack.config.js +43 -0
  98. 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
  99. package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/app.js +8 -0
  100. package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/app2.js +6 -0
  101. package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/ice.png +0 -0
  102. package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/ice2.jpg +0 -0
  103. package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/rect.svg +4 -0
  104. package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/rect2.svg +4 -0
  105. package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/styles.css +8 -0
  106. package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/src/styles2.css +8 -0
  107. package/test/use-cases/css-and-assets-distribution-via-mini-css-extract-plugin/webpack.config.js +51 -0
  108. package/test/use-cases/css-and-assets-via-extract-text-plugin/css-and-assets-via-extract-text-plugin.test.js +87 -0
  109. package/test/use-cases/css-and-assets-via-extract-text-plugin/src/feature-one.css +7 -0
  110. package/test/use-cases/css-and-assets-via-extract-text-plugin/src/feature-one.js +3 -0
  111. package/test/use-cases/css-and-assets-via-extract-text-plugin/src/feature-two.css +3 -0
  112. package/test/use-cases/css-and-assets-via-extract-text-plugin/src/feature-two.js +1 -0
  113. package/test/use-cases/css-and-assets-via-extract-text-plugin/src/ice.png +0 -0
  114. package/test/use-cases/css-and-assets-via-extract-text-plugin/webpack.config.js +46 -0
  115. package/test/use-cases/css-and-assets-via-style-loader/css-and-assets-via-style-loader.test.js +46 -0
  116. package/test/use-cases/css-and-assets-via-style-loader/src/app.js +6 -0
  117. package/test/use-cases/css-and-assets-via-style-loader/src/ice.png +0 -0
  118. package/test/use-cases/css-and-assets-via-style-loader/src/styles.css +7 -0
  119. package/test/use-cases/css-and-assets-via-style-loader/webpack.config.js +46 -0
  120. package/test/use-cases/cyclic-dependencies/cyclic.test.js +24 -0
  121. package/test/use-cases/cyclic-dependencies/src/a.js +3 -0
  122. package/test/use-cases/cyclic-dependencies/src/b.js +3 -0
  123. package/test/use-cases/cyclic-dependencies/src/root.js +3 -0
  124. package/test/use-cases/cyclic-dependencies/webpack.config.js +24 -0
  125. package/test/use-cases/data-providers/data-providers.test.js +111 -0
  126. package/test/use-cases/data-providers/src/first.js +2 -0
  127. package/test/use-cases/data-providers/src/second.js +2 -0
  128. package/test/use-cases/data-providers/src/third.js +2 -0
  129. package/test/use-cases/data-providers/webpack.config.js +73 -0
  130. package/test/use-cases/data-providers/webpack.config.with-map.js +33 -0
  131. package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/ensure-runtime-overwrite-of-mini-css-extract-plugin.test.js +86 -0
  132. package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/app.js +5 -0
  133. package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/app2.js +5 -0
  134. package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/ice.png +0 -0
  135. package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/ice2.jpg +0 -0
  136. package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/rect.svg +4 -0
  137. package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/rect2.svg +4 -0
  138. package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/styles.css +8 -0
  139. package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/src/styles2.css +8 -0
  140. package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/webpack.after.config.js +51 -0
  141. package/test/use-cases/ensure-runtime-overwrite-of-mini-css-extract-plugin/webpack.before.config.js +51 -0
  142. package/test/use-cases/jsonp-function-name/jsonp-function-name.test.js +37 -0
  143. package/test/use-cases/jsonp-function-name/src/app.js +1 -0
  144. package/test/use-cases/jsonp-function-name/src/foo.js +2 -0
  145. package/test/use-cases/jsonp-function-name/webpack.config.js +35 -0
  146. package/test/use-cases/jsonp-function-name-default/jsonp-function-name-default.test.js +39 -0
  147. package/test/use-cases/jsonp-function-name-default/src/app.js +1 -0
  148. package/test/use-cases/jsonp-function-name-default/src/foo.js +2 -0
  149. package/test/use-cases/jsonp-function-name-default/webpack.config.js +34 -0
  150. package/test/use-cases/location-prefix/location-prefix.test.js +29 -0
  151. package/test/use-cases/location-prefix/src/simple.js +6 -0
  152. package/test/use-cases/location-prefix/webpack.config.js +25 -0
  153. package/test/use-cases/provided-module-replacement/provided-module-replacement.test.js +63 -0
  154. package/test/use-cases/provided-module-replacement/src/app.js +3 -0
  155. package/test/use-cases/provided-module-replacement/webpack.config.with-map.js +33 -0
  156. package/test/use-cases/provided-module-replacement/webpack.config.with-object.js +34 -0
  157. package/test/use-cases/provided-modules-replacement-with-amd-target/provided-modules-replacement-with-amd-target.test.js +62 -0
  158. package/test/use-cases/provided-modules-replacement-with-amd-target/src/app.js +3 -0
  159. package/test/use-cases/provided-modules-replacement-with-amd-target/webpack.config.js +41 -0
  160. package/test/use-cases/qunit-test-wrm-web-resource/qunit-test-wrm-web-resource.test.js +157 -0
  161. package/test/use-cases/qunit-test-wrm-web-resource/src/app.2.js +6 -0
  162. package/test/use-cases/qunit-test-wrm-web-resource/src/app.js +8 -0
  163. package/test/use-cases/qunit-test-wrm-web-resource/src/bar-dep.js +8 -0
  164. package/test/use-cases/qunit-test-wrm-web-resource/src/bar-dep_test.js +1 -0
  165. package/test/use-cases/qunit-test-wrm-web-resource/src/foo-async.js +3 -0
  166. package/test/use-cases/qunit-test-wrm-web-resource/src/foo-dep.js +4 -0
  167. package/test/use-cases/qunit-test-wrm-web-resource/src/foo-dep_test.js +1 -0
  168. package/test/use-cases/qunit-test-wrm-web-resource/webpack.config.js +24 -0
  169. package/test/use-cases/resource-parameters/resource-parameters.test.js +77 -0
  170. package/test/use-cases/resource-parameters/src/app.js +12 -0
  171. package/test/use-cases/resource-parameters/src/ice.png +0 -0
  172. package/test/use-cases/resource-parameters/src/ice2.jpg +0 -0
  173. package/test/use-cases/resource-parameters/src/rect.svg +4 -0
  174. package/test/use-cases/resource-parameters/webpack.config.js +62 -0
  175. package/test/use-cases/resource-parameters/webpack.svg.config.js +30 -0
  176. package/test/use-cases/simple/simple.test.js +83 -0
  177. package/test/use-cases/simple/src/simple.js +3 -0
  178. package/test/use-cases/simple/webpack.config.js +24 -0
  179. package/test/use-cases/single-runtime-chunk/single-runtime-chunk.test.js +132 -0
  180. package/test/use-cases/single-runtime-chunk/src/first.js +2 -0
  181. package/test/use-cases/single-runtime-chunk/src/second.js +2 -0
  182. package/test/use-cases/single-runtime-chunk/src/shared.js +3 -0
  183. package/test/use-cases/single-runtime-chunk/src/third.js +2 -0
  184. package/test/use-cases/single-runtime-chunk/webpack.config.js +33 -0
  185. package/test/use-cases/specify-asset-dev-hash/specify-asset-dev-hash.test.js +33 -0
  186. package/test/use-cases/specify-asset-dev-hash/src/feature.js +6 -0
  187. package/test/use-cases/specify-asset-dev-hash/src/library.js +6 -0
  188. package/test/use-cases/specify-asset-dev-hash/webpack.config.js +71 -0
  189. package/test/use-cases/specify-conditions/specify-conditions.test.js +106 -0
  190. package/test/use-cases/specify-conditions/src/app.js +5 -0
  191. package/test/use-cases/specify-conditions/webpack.config.js +65 -0
  192. package/test/use-cases/specify-explicit-context/specify-explicit-context.test.js +89 -0
  193. package/test/use-cases/specify-explicit-context/src/app.js +5 -0
  194. package/test/use-cases/specify-explicit-context/webpack.config.js +34 -0
  195. package/test/use-cases/specify-explicit-context-no-autogenerated/specify-explicit-context-no-autogenerated.test.js +84 -0
  196. package/test/use-cases/specify-explicit-context-no-autogenerated/src/app.js +5 -0
  197. package/test/use-cases/specify-explicit-context-no-autogenerated/webpack.config.js +35 -0
  198. package/test/use-cases/specify-explicit-name/specify-explicit-name.test.js +110 -0
  199. package/test/use-cases/specify-explicit-name/src/app.js +5 -0
  200. package/test/use-cases/specify-explicit-name/webpack.config.js +43 -0
  201. package/test/use-cases/specify-explicit-state/specify-explicit-state.test.js +96 -0
  202. package/test/use-cases/specify-explicit-state/src/app.js +5 -0
  203. package/test/use-cases/specify-explicit-state/webpack.config.js +51 -0
  204. package/test/use-cases/specify-transformation/disable-transformations.test.js +77 -0
  205. package/test/use-cases/specify-transformation/extend-transformations.test.js +69 -0
  206. package/test/use-cases/specify-transformation/specify-transformation.test.js +100 -0
  207. package/test/use-cases/specify-transformation/src/app.js +13 -0
  208. package/test/use-cases/specify-transformation/src/ice.png +0 -0
  209. package/test/use-cases/specify-transformation/src/rect.svg +4 -0
  210. package/test/use-cases/specify-transformation/src/test.html +1 -0
  211. package/test/use-cases/specify-transformation/src/test.less +1 -0
  212. package/test/use-cases/specify-transformation/src/test.txt +1 -0
  213. package/test/use-cases/specify-transformation/webpack.disable-tranformations.config.js +31 -0
  214. package/test/use-cases/specify-transformation/webpack.extend-tranformations.config.js +34 -0
  215. package/test/use-cases/specify-transformation/webpack.specify-transformations.config.js +35 -0
  216. package/test/use-cases/split-chunks/split-chunks.test.js +102 -0
  217. package/test/use-cases/split-chunks/src/app.js +7 -0
  218. package/test/use-cases/split-chunks/src/app2.js +7 -0
  219. package/test/use-cases/split-chunks/src/bar.js +2 -0
  220. package/test/use-cases/split-chunks/src/foo.js +2 -0
  221. package/test/use-cases/split-chunks/src/foo2.js +2 -0
  222. package/test/use-cases/split-chunks/webpack.config.js +42 -0
  223. package/test/use-cases/split-chunks-with-runtime/split-chunks-with-runtime.test.js +114 -0
  224. package/test/use-cases/split-chunks-with-runtime/src/app.js +7 -0
  225. package/test/use-cases/split-chunks-with-runtime/src/app2.js +7 -0
  226. package/test/use-cases/split-chunks-with-runtime/src/bar.js +2 -0
  227. package/test/use-cases/split-chunks-with-runtime/src/foo.js +2 -0
  228. package/test/use-cases/split-chunks-with-runtime/src/foo2.js +2 -0
  229. package/test/use-cases/split-chunks-with-runtime/webpack.config.js +43 -0
  230. package/test/use-cases/split-chunks-with-tests/split-chunks-with-tests.test.js +216 -0
  231. package/test/use-cases/split-chunks-with-tests/src/app.js +7 -0
  232. package/test/use-cases/split-chunks-with-tests/src/app2.js +7 -0
  233. package/test/use-cases/split-chunks-with-tests/src/bar.js +2 -0
  234. package/test/use-cases/split-chunks-with-tests/src/bar_test.js +1 -0
  235. package/test/use-cases/split-chunks-with-tests/src/foo.js +2 -0
  236. package/test/use-cases/split-chunks-with-tests/src/foo2.js +2 -0
  237. package/test/use-cases/split-chunks-with-tests/src/foo_test.js +1 -0
  238. package/test/use-cases/split-chunks-with-tests/webpack.config.js +43 -0
  239. package/test/use-cases/standalone/src/standalone-1.js +1 -0
  240. package/test/use-cases/standalone/src/standalone-2.js +1 -0
  241. package/test/use-cases/standalone/standalone.test.js +53 -0
  242. package/test/use-cases/standalone/webpack.config.js +25 -0
  243. package/test/use-cases/wrm-dependency-loading/src-amd/app.js +7 -0
  244. package/test/use-cases/wrm-dependency-loading/src-es6/app.js +7 -0
  245. package/test/use-cases/wrm-dependency-loading/webpack.config.amd.js +22 -0
  246. package/test/use-cases/wrm-dependency-loading/webpack.config.es6.js +22 -0
  247. package/test/use-cases/wrm-dependency-loading/wrm-dependency-loading.test.js +60 -0
  248. package/test/use-cases/wrm-manifest-path/src/a.js +3 -0
  249. package/test/use-cases/wrm-manifest-path/src/app.js +3 -0
  250. package/test/use-cases/wrm-manifest-path/src/app2.js +3 -0
  251. package/test/use-cases/wrm-manifest-path/src/b.js +3 -0
  252. package/test/use-cases/wrm-manifest-path/webpack.config.js +27 -0
  253. package/test/use-cases/wrm-manifest-path/wrm-manifest-path.test.js +57 -0
  254. package/test/use-cases/wrm-resource-loading/src-amd/app.js +6 -0
  255. package/test/use-cases/wrm-resource-loading/src-es6/app.js +5 -0
  256. package/test/use-cases/wrm-resource-loading/src-relative/app.js +5 -0
  257. package/test/use-cases/wrm-resource-loading/webpack.config.amd.js +23 -0
  258. package/test/use-cases/wrm-resource-loading/webpack.config.es6.js +23 -0
  259. package/test/use-cases/wrm-resource-loading/webpack.config.relative.js +23 -0
  260. package/test/use-cases/wrm-resource-loading/wrm-resource-loading.test.js +89 -0
@@ -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;