@openedx/frontend-build 15.0.0-alpha.2 → 15.0.0-alpha.20

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 (220) hide show
  1. package/README.md +1 -1
  2. package/config/.eslintrc.js +1 -0
  3. package/config/data/paragonUtils.js +171 -0
  4. package/config/jest/setupTest.js +35 -0
  5. package/config/jest.config.js +4 -1
  6. package/config/webpack.common.config.js +44 -0
  7. package/config/webpack.dev-stage.config.js +1 -0
  8. package/config/webpack.dev.config.js +57 -35
  9. package/config/webpack.prod.config.js +2 -1
  10. package/lib/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.js +126 -0
  11. package/lib/plugins/paragon-webpack-plugin/index.js +3 -0
  12. package/lib/plugins/paragon-webpack-plugin/utils/assetUtils.js +75 -0
  13. package/lib/plugins/paragon-webpack-plugin/utils/htmlUtils.js +69 -0
  14. package/lib/plugins/paragon-webpack-plugin/utils/index.js +9 -0
  15. package/lib/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.js +120 -0
  16. package/lib/plugins/paragon-webpack-plugin/utils/scriptUtils.js +144 -0
  17. package/lib/plugins/paragon-webpack-plugin/utils/stylesheetUtils.js +107 -0
  18. package/lib/plugins/paragon-webpack-plugin/utils/tagUtils.js +58 -0
  19. package/package.json +22 -14
  20. package/.eslintignore +0 -5
  21. package/.eslintrc.js +0 -10
  22. package/.github/workflows/add-depr-ticket-to-depr-board.yml +0 -19
  23. package/.github/workflows/add-remove-label-on-comment.yml +0 -20
  24. package/.github/workflows/ci.yml +0 -30
  25. package/.github/workflows/commitlint.yml +0 -17
  26. package/.github/workflows/lockfileversion-check.yml +0 -13
  27. package/.github/workflows/release.yml +0 -34
  28. package/.github/workflows/self-assign-issue.yml +0 -12
  29. package/.github/workflows/sync-master-alpha.yml +0 -35
  30. package/.nvmrc +0 -1
  31. package/coverage/clover.xml +0 -6
  32. package/coverage/coverage-final.json +0 -1
  33. package/coverage/lcov-report/base.css +0 -224
  34. package/coverage/lcov-report/block-navigation.js +0 -87
  35. package/coverage/lcov-report/favicon.png +0 -0
  36. package/coverage/lcov-report/index.html +0 -101
  37. package/coverage/lcov-report/prettify.css +0 -1
  38. package/coverage/lcov-report/prettify.js +0 -2
  39. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  40. package/coverage/lcov-report/sorter.js +0 -196
  41. package/coverage/lcov.info +0 -0
  42. package/docs/0001-non-usage-of-gatsby.rst +0 -37
  43. package/docs/0002-js-environment-config.md +0 -47
  44. package/docs/0003-fedx-scripts-serve.md +0 -37
  45. package/example/.env +0 -0
  46. package/example/.env.development +0 -3
  47. package/example/.env.test +0 -2
  48. package/example/.eslintignore +0 -5
  49. package/example/.eslintrc.js +0 -3
  50. package/example/dist/1382e1cbf8d733d7301cdd212192bfea.jpg +0 -0
  51. package/example/dist/652.70be34739115e11aaeb3.js +0 -3
  52. package/example/dist/652.70be34739115e11aaeb3.js.LICENSE.txt +0 -41
  53. package/example/dist/652.70be34739115e11aaeb3.js.map +0 -1
  54. package/example/dist/app.9b26aa9c728d62e6064d.css +0 -3
  55. package/example/dist/app.9b26aa9c728d62e6064d.css.map +0 -1
  56. package/example/dist/app.9b26aa9c728d62e6064d.js +0 -2
  57. package/example/dist/app.9b26aa9c728d62e6064d.js.map +0 -1
  58. package/example/dist/babel/App.js +0 -94
  59. package/example/dist/babel/App.js.map +0 -1
  60. package/example/dist/babel/App.test.jsx +0 -11
  61. package/example/dist/babel/Image.tsx +0 -16
  62. package/example/dist/babel/__snapshots__/App.test.jsx.snap +0 -120
  63. package/example/dist/babel/apple.jpg +0 -0
  64. package/example/dist/babel/apple.svg +0 -1
  65. package/example/dist/babel/index.js +0 -13
  66. package/example/dist/babel/index.js.map +0 -1
  67. package/example/dist/babel/style.scss +0 -9
  68. package/example/dist/cb28cdb1468c915e27e5cec9af64f22f.svg +0 -1
  69. package/example/dist/index.html +0 -4
  70. package/example/dist/report.html +0 -39
  71. package/example/dist/runtime.40856db71d718a3e9d37.js +0 -2
  72. package/example/dist/runtime.40856db71d718a3e9d37.js.map +0 -1
  73. package/example/env.config.js +0 -6
  74. package/example/node_modules/.package-lock.json +0 -98
  75. package/example/node_modules/js-tokens/CHANGELOG.md +0 -151
  76. package/example/node_modules/js-tokens/LICENSE +0 -21
  77. package/example/node_modules/js-tokens/README.md +0 -240
  78. package/example/node_modules/js-tokens/index.js +0 -23
  79. package/example/node_modules/js-tokens/package.json +0 -30
  80. package/example/node_modules/loose-envify/LICENSE +0 -21
  81. package/example/node_modules/loose-envify/README.md +0 -45
  82. package/example/node_modules/loose-envify/cli.js +0 -16
  83. package/example/node_modules/loose-envify/custom.js +0 -4
  84. package/example/node_modules/loose-envify/index.js +0 -3
  85. package/example/node_modules/loose-envify/loose-envify.js +0 -36
  86. package/example/node_modules/loose-envify/package.json +0 -36
  87. package/example/node_modules/loose-envify/replace.js +0 -65
  88. package/example/node_modules/object-assign/index.js +0 -90
  89. package/example/node_modules/object-assign/license +0 -21
  90. package/example/node_modules/object-assign/package.json +0 -42
  91. package/example/node_modules/object-assign/readme.md +0 -61
  92. package/example/node_modules/prop-types/LICENSE +0 -21
  93. package/example/node_modules/prop-types/README.md +0 -302
  94. package/example/node_modules/prop-types/checkPropTypes.js +0 -103
  95. package/example/node_modules/prop-types/factory.js +0 -19
  96. package/example/node_modules/prop-types/factoryWithThrowingShims.js +0 -65
  97. package/example/node_modules/prop-types/factoryWithTypeCheckers.js +0 -610
  98. package/example/node_modules/prop-types/index.js +0 -19
  99. package/example/node_modules/prop-types/lib/ReactPropTypesSecret.js +0 -12
  100. package/example/node_modules/prop-types/lib/has.js +0 -1
  101. package/example/node_modules/prop-types/package.json +0 -60
  102. package/example/node_modules/prop-types/prop-types.js +0 -1315
  103. package/example/node_modules/prop-types/prop-types.min.js +0 -1
  104. package/example/node_modules/react/LICENSE +0 -21
  105. package/example/node_modules/react/README.md +0 -13
  106. package/example/node_modules/react/build-info.json +0 -8
  107. package/example/node_modules/react/cjs/react-jsx-dev-runtime.development.js +0 -889
  108. package/example/node_modules/react/cjs/react-jsx-dev-runtime.production.min.js +0 -9
  109. package/example/node_modules/react/cjs/react-jsx-runtime.development.js +0 -911
  110. package/example/node_modules/react/cjs/react-jsx-runtime.production.min.js +0 -10
  111. package/example/node_modules/react/cjs/react.development.js +0 -1912
  112. package/example/node_modules/react/cjs/react.production.min.js +0 -25
  113. package/example/node_modules/react/index.js +0 -7
  114. package/example/node_modules/react/jsx-dev-runtime.js +0 -7
  115. package/example/node_modules/react/jsx-runtime.js +0 -7
  116. package/example/node_modules/react/package.json +0 -44
  117. package/example/node_modules/react/umd/react.development.js +0 -3318
  118. package/example/node_modules/react/umd/react.production.min.js +0 -32
  119. package/example/node_modules/react/umd/react.profiling.min.js +0 -39
  120. package/example/node_modules/react-dom/LICENSE +0 -21
  121. package/example/node_modules/react-dom/README.md +0 -54
  122. package/example/node_modules/react-dom/build-info.json +0 -8
  123. package/example/node_modules/react-dom/cjs/react-dom-server.browser.development.js +0 -4043
  124. package/example/node_modules/react-dom/cjs/react-dom-server.browser.production.min.js +0 -54
  125. package/example/node_modules/react-dom/cjs/react-dom-server.node.development.js +0 -4085
  126. package/example/node_modules/react-dom/cjs/react-dom-server.node.production.min.js +0 -55
  127. package/example/node_modules/react-dom/cjs/react-dom-test-utils.development.js +0 -1480
  128. package/example/node_modules/react-dom/cjs/react-dom-test-utils.production.min.js +0 -35
  129. package/example/node_modules/react-dom/cjs/react-dom-unstable-fizz.browser.development.js +0 -141
  130. package/example/node_modules/react-dom/cjs/react-dom-unstable-fizz.browser.production.min.js +0 -11
  131. package/example/node_modules/react-dom/cjs/react-dom-unstable-fizz.node.development.js +0 -162
  132. package/example/node_modules/react-dom/cjs/react-dom-unstable-fizz.node.production.min.js +0 -12
  133. package/example/node_modules/react-dom/cjs/react-dom-unstable-native-dependencies.development.js +0 -1629
  134. package/example/node_modules/react-dom/cjs/react-dom-unstable-native-dependencies.production.min.js +0 -31
  135. package/example/node_modules/react-dom/cjs/react-dom.development.js +0 -25012
  136. package/example/node_modules/react-dom/cjs/react-dom.production.min.js +0 -292
  137. package/example/node_modules/react-dom/cjs/react-dom.profiling.min.js +0 -299
  138. package/example/node_modules/react-dom/index.js +0 -38
  139. package/example/node_modules/react-dom/package.json +0 -60
  140. package/example/node_modules/react-dom/profiling.js +0 -38
  141. package/example/node_modules/react-dom/server.browser.js +0 -7
  142. package/example/node_modules/react-dom/server.js +0 -3
  143. package/example/node_modules/react-dom/server.node.js +0 -7
  144. package/example/node_modules/react-dom/test-utils.js +0 -7
  145. package/example/node_modules/react-dom/umd/react-dom-server.browser.development.js +0 -4147
  146. package/example/node_modules/react-dom/umd/react-dom-server.browser.production.min.js +0 -45
  147. package/example/node_modules/react-dom/umd/react-dom-test-utils.development.js +0 -1499
  148. package/example/node_modules/react-dom/umd/react-dom-test-utils.production.min.js +0 -30
  149. package/example/node_modules/react-dom/umd/react-dom-unstable-fizz.browser.development.js +0 -141
  150. package/example/node_modules/react-dom/umd/react-dom-unstable-fizz.browser.production.min.js +0 -10
  151. package/example/node_modules/react-dom/umd/react-dom-unstable-native-dependencies.development.js +0 -1628
  152. package/example/node_modules/react-dom/umd/react-dom-unstable-native-dependencies.production.min.js +0 -28
  153. package/example/node_modules/react-dom/umd/react-dom.development.js +0 -25147
  154. package/example/node_modules/react-dom/umd/react-dom.production.min.js +0 -239
  155. package/example/node_modules/react-dom/umd/react-dom.profiling.min.js +0 -247
  156. package/example/node_modules/react-dom/unstable-fizz.browser.js +0 -7
  157. package/example/node_modules/react-dom/unstable-fizz.js +0 -3
  158. package/example/node_modules/react-dom/unstable-fizz.node.js +0 -7
  159. package/example/node_modules/react-dom/unstable-native-dependencies.js +0 -7
  160. package/example/node_modules/react-is/LICENSE +0 -21
  161. package/example/node_modules/react-is/README.md +0 -104
  162. package/example/node_modules/react-is/build-info.json +0 -8
  163. package/example/node_modules/react-is/cjs/react-is.development.js +0 -181
  164. package/example/node_modules/react-is/cjs/react-is.production.min.js +0 -15
  165. package/example/node_modules/react-is/index.js +0 -7
  166. package/example/node_modules/react-is/package.json +0 -27
  167. package/example/node_modules/react-is/umd/react-is.development.js +0 -181
  168. package/example/node_modules/react-is/umd/react-is.production.min.js +0 -13
  169. package/example/node_modules/react-test-renderer/LICENSE +0 -21
  170. package/example/node_modules/react-test-renderer/README.md +0 -26
  171. package/example/node_modules/react-test-renderer/build-info.json +0 -8
  172. package/example/node_modules/react-test-renderer/cjs/react-test-renderer-shallow.development.js +0 -1019
  173. package/example/node_modules/react-test-renderer/cjs/react-test-renderer-shallow.production.min.js +0 -35
  174. package/example/node_modules/react-test-renderer/cjs/react-test-renderer.development.js +0 -15596
  175. package/example/node_modules/react-test-renderer/cjs/react-test-renderer.production.min.js +0 -181
  176. package/example/node_modules/react-test-renderer/index.js +0 -7
  177. package/example/node_modules/react-test-renderer/package.json +0 -41
  178. package/example/node_modules/react-test-renderer/shallow.js +0 -7
  179. package/example/node_modules/react-test-renderer/umd/react-test-renderer-shallow.development.js +0 -1176
  180. package/example/node_modules/react-test-renderer/umd/react-test-renderer-shallow.production.min.js +0 -31
  181. package/example/node_modules/react-test-renderer/umd/react-test-renderer.development.js +0 -15709
  182. package/example/node_modules/react-test-renderer/umd/react-test-renderer.production.min.js +0 -151
  183. package/example/node_modules/scheduler/LICENSE +0 -21
  184. package/example/node_modules/scheduler/README.md +0 -9
  185. package/example/node_modules/scheduler/build-info.json +0 -8
  186. package/example/node_modules/scheduler/cjs/scheduler-tracing.development.js +0 -349
  187. package/example/node_modules/scheduler/cjs/scheduler-tracing.production.min.js +0 -10
  188. package/example/node_modules/scheduler/cjs/scheduler-tracing.profiling.min.js +0 -17
  189. package/example/node_modules/scheduler/cjs/scheduler-unstable_mock.development.js +0 -857
  190. package/example/node_modules/scheduler/cjs/scheduler-unstable_mock.production.min.js +0 -20
  191. package/example/node_modules/scheduler/cjs/scheduler.development.js +0 -858
  192. package/example/node_modules/scheduler/cjs/scheduler.production.min.js +0 -21
  193. package/example/node_modules/scheduler/index.js +0 -7
  194. package/example/node_modules/scheduler/package.json +0 -39
  195. package/example/node_modules/scheduler/tracing-profiling.js +0 -7
  196. package/example/node_modules/scheduler/tracing.js +0 -7
  197. package/example/node_modules/scheduler/umd/scheduler-tracing.development.js +0 -80
  198. package/example/node_modules/scheduler/umd/scheduler-tracing.production.min.js +0 -80
  199. package/example/node_modules/scheduler/umd/scheduler-tracing.profiling.min.js +0 -80
  200. package/example/node_modules/scheduler/umd/scheduler-unstable_mock.development.js +0 -857
  201. package/example/node_modules/scheduler/umd/scheduler-unstable_mock.production.min.js +0 -17
  202. package/example/node_modules/scheduler/umd/scheduler.development.js +0 -152
  203. package/example/node_modules/scheduler/umd/scheduler.production.min.js +0 -146
  204. package/example/node_modules/scheduler/umd/scheduler.profiling.min.js +0 -146
  205. package/example/node_modules/scheduler/unstable_mock.js +0 -7
  206. package/example/package-lock.json +0 -110
  207. package/example/package.json +0 -24
  208. package/example/public/index.html +0 -13
  209. package/example/src/App.jsx +0 -43
  210. package/example/src/App.test.jsx +0 -11
  211. package/example/src/Image.tsx +0 -16
  212. package/example/src/__snapshots__/App.test.jsx.snap +0 -120
  213. package/example/src/apple.jpg +0 -0
  214. package/example/src/apple.svg +0 -1
  215. package/example/src/index.jsx +0 -13
  216. package/example/src/style.scss +0 -9
  217. package/example/tsconfig.json +0 -16
  218. package/openedx.yaml +0 -10
  219. package/renovate.json +0 -22
  220. package/smoke-test.sh +0 -11
@@ -0,0 +1,69 @@
1
+ const { sources } = require('webpack');
2
+
3
+ const { getCssAssetsFromCompilation } = require('./assetUtils');
4
+ const { generateScriptContents, insertScriptContentsIntoDocument } = require('./scriptUtils');
5
+
6
+ /**
7
+ * Injects metadata into the HTML document by modifying the 'index.html' asset in the compilation.
8
+ *
9
+ * @param {Object} compilation - The Webpack compilation object.
10
+ * @param {Object} options - The options object.
11
+ * @param {Object} options.paragonThemeCss - The Paragon theme CSS object.
12
+ * @param {string} options.paragonVersion - The version of the Paragon theme.
13
+ * @param {Object} options.brandThemeCss - The brand theme CSS object.
14
+ * @param {string} options.brandVersion - The version of the brand theme.
15
+ * @return {Object|undefined} The script contents object if the 'index.html' asset exists, otherwise undefined.
16
+ */
17
+ function injectMetadataIntoDocument(compilation, {
18
+ paragonThemeCss,
19
+ paragonVersion,
20
+ brandThemeCss,
21
+ brandVersion,
22
+ }) {
23
+ const file = compilation.getAsset('index.html');
24
+ if (!file) {
25
+ return undefined;
26
+ }
27
+ const {
28
+ coreCssAsset: paragonCoreCssAsset,
29
+ themeVariantCssAssets: paragonThemeVariantCssAssets,
30
+ } = getCssAssetsFromCompilation(compilation, {
31
+ brandThemeCss,
32
+ paragonThemeCss,
33
+ });
34
+ const {
35
+ coreCssAsset: brandCoreCssAsset,
36
+ themeVariantCssAssets: brandThemeVariantCssAssets,
37
+ } = getCssAssetsFromCompilation(compilation, {
38
+ isBrandOverride: true,
39
+ brandThemeCss,
40
+ paragonThemeCss,
41
+ });
42
+
43
+ const scriptContents = generateScriptContents({
44
+ paragonCoreCssAsset,
45
+ paragonThemeVariantCssAssets,
46
+ brandCoreCssAsset,
47
+ brandThemeVariantCssAssets,
48
+ paragonThemeCss,
49
+ paragonVersion,
50
+ brandThemeCss,
51
+ brandVersion,
52
+ });
53
+
54
+ const originalSource = file.source.source();
55
+ const newSource = insertScriptContentsIntoDocument({
56
+ originalSource,
57
+ coreCssAsset: paragonCoreCssAsset,
58
+ themeVariantCssAssets: paragonThemeVariantCssAssets,
59
+ scriptContents,
60
+ });
61
+
62
+ compilation.updateAsset('index.html', new sources.RawSource(newSource.source()));
63
+
64
+ return scriptContents;
65
+ }
66
+
67
+ module.exports = {
68
+ injectMetadataIntoDocument,
69
+ };
@@ -0,0 +1,9 @@
1
+ const { getParagonStylesheetUrls, injectParagonCoreStylesheets, injectParagonThemeVariantStylesheets } = require('./paragonStylesheetUtils');
2
+ const { injectMetadataIntoDocument } = require('./htmlUtils');
3
+
4
+ module.exports = {
5
+ injectMetadataIntoDocument,
6
+ getParagonStylesheetUrls,
7
+ injectParagonCoreStylesheets,
8
+ injectParagonThemeVariantStylesheets,
9
+ };
@@ -0,0 +1,120 @@
1
+ const { insertStylesheetsIntoDocument } = require('./stylesheetUtils');
2
+ const { handleVersionSubstitution } = require('./tagUtils');
3
+
4
+ /**
5
+ * Injects Paragon core stylesheets into the document.
6
+ *
7
+ * @param {Object} options - The options object.
8
+ * @param {string|object} options.source - The source HTML document.
9
+ * @param {Object} options.paragonCoreCss - The Paragon core CSS object.
10
+ * @param {Object} options.paragonThemeCss - The Paragon theme CSS object.
11
+ * @param {Object} options.brandThemeCss - The brand theme CSS object.
12
+ * @return {string|object} The modified HTML document with Paragon core stylesheets injected.
13
+ */
14
+ function injectParagonCoreStylesheets({
15
+ source,
16
+ paragonCoreCss,
17
+ paragonThemeCss,
18
+ brandThemeCss,
19
+ }) {
20
+ return insertStylesheetsIntoDocument({
21
+ source,
22
+ urls: paragonCoreCss.urls,
23
+ paragonThemeCss,
24
+ brandThemeCss,
25
+ });
26
+ }
27
+
28
+ /**
29
+ * Injects Paragon theme variant stylesheets into the document.
30
+ *
31
+ * @param {Object} options - The options object.
32
+ * @param {string|object} options.source - The source HTML document.
33
+ * @param {Object} options.paragonThemeVariantCss - The Paragon theme variant CSS object.
34
+ * @param {Object} options.paragonThemeCss - The Paragon theme CSS object.
35
+ * @param {Object} options.brandThemeCss - The brand theme CSS object.
36
+ * @return {string|object} The modified HTML document with Paragon theme variant stylesheets injected.
37
+ */
38
+ function injectParagonThemeVariantStylesheets({
39
+ source,
40
+ paragonThemeVariantCss,
41
+ paragonThemeCss,
42
+ brandThemeCss,
43
+ }) {
44
+ let newSource = source;
45
+ Object.values(paragonThemeVariantCss).forEach(({ urls }) => {
46
+ newSource = insertStylesheetsIntoDocument({
47
+ source: typeof newSource === 'object' ? newSource.source() : newSource,
48
+ urls,
49
+ paragonThemeCss,
50
+ brandThemeCss,
51
+ });
52
+ });
53
+ return newSource;
54
+ }
55
+ /**
56
+ * Retrieves the URLs of the Paragon stylesheets based on the provided theme URLs, Paragon version, and brand version.
57
+ *
58
+ * @param {Object} options - The options object.
59
+ * @param {Object} options.paragonThemeUrls - The URLs of the Paragon theme.
60
+ * @param {string} options.paragonVersion - The version of the Paragon theme.
61
+ * @param {string} options.brandVersion - The version of the brand theme.
62
+ * @return {Object} An object containing the URLs of the Paragon stylesheets.
63
+ */
64
+ function getParagonStylesheetUrls({ paragonThemeUrls, paragonVersion, brandVersion }) {
65
+ const paragonCoreCssUrl = typeof paragonThemeUrls.core.urls === 'object' ? paragonThemeUrls.core.urls.default : paragonThemeUrls.core.url;
66
+ const brandCoreCssUrl = typeof paragonThemeUrls.core.urls === 'object' ? paragonThemeUrls.core.urls.brandOverride : undefined;
67
+
68
+ const defaultThemeVariants = paragonThemeUrls.defaults || {};
69
+
70
+ const coreCss = {
71
+ urls: {
72
+ default: handleVersionSubstitution({ url: paragonCoreCssUrl, wildcardKeyword: '$paragonVersion', localVersion: paragonVersion }),
73
+ brandOverride: handleVersionSubstitution({ url: brandCoreCssUrl, wildcardKeyword: '$brandVersion', localVersion: brandVersion }),
74
+ },
75
+ };
76
+
77
+ const themeVariantsCss = {};
78
+ const themeVariantsEntries = Object.entries(paragonThemeUrls.variants || {});
79
+ themeVariantsEntries.forEach(([themeVariant, { url, urls }]) => {
80
+ const themeVariantMetadata = { urls: null };
81
+ if (url) {
82
+ themeVariantMetadata.urls = {
83
+ default: handleVersionSubstitution({
84
+ url,
85
+ wildcardKeyword: '$paragonVersion',
86
+ localVersion: paragonVersion,
87
+ }),
88
+ // If there is no brand override URL, then we don't need to do any version substitution
89
+ // but we still need to return the property.
90
+ brandOverride: undefined,
91
+ };
92
+ } else {
93
+ themeVariantMetadata.urls = {
94
+ default: handleVersionSubstitution({
95
+ url: urls.default,
96
+ wildcardKeyword: '$paragonVersion',
97
+ localVersion: paragonVersion,
98
+ }),
99
+ brandOverride: handleVersionSubstitution({
100
+ url: urls.brandOverride,
101
+ wildcardKeyword: '$brandVersion',
102
+ localVersion: brandVersion,
103
+ }),
104
+ };
105
+ }
106
+ themeVariantsCss[themeVariant] = themeVariantMetadata;
107
+ });
108
+
109
+ return {
110
+ core: coreCss,
111
+ variants: themeVariantsCss,
112
+ defaults: defaultThemeVariants,
113
+ };
114
+ }
115
+
116
+ module.exports = {
117
+ injectParagonCoreStylesheets,
118
+ injectParagonThemeVariantStylesheets,
119
+ getParagonStylesheetUrls,
120
+ };
@@ -0,0 +1,144 @@
1
+ const { sources } = require('webpack');
2
+ const parse5 = require('parse5');
3
+
4
+ const { getDescendantByTag, minifyScript } = require('./tagUtils');
5
+
6
+ /**
7
+ * Finds the insertion point for a script in an HTML document.
8
+ *
9
+ * @param {Object} options - The options object.
10
+ * @param {Object} options.document - The parsed HTML document.
11
+ * @param {string} options.originalSource - The original source code of the HTML document.
12
+ * @throws {Error} If the body element is missing in the HTML document.
13
+ * @return {number} The insertion point for the script in the HTML document.
14
+ */
15
+ function findScriptInsertionPoint({ document, originalSource }) {
16
+ const bodyElement = getDescendantByTag(document, 'body');
17
+ if (!bodyElement) {
18
+ throw new Error('Missing body element in index.html.');
19
+ }
20
+
21
+ // determine script insertion point
22
+ if (bodyElement.sourceCodeLocation?.endTag) {
23
+ return bodyElement.sourceCodeLocation.endTag.startOffset;
24
+ }
25
+
26
+ // less accurate fallback
27
+ return originalSource.indexOf('</body>');
28
+ }
29
+
30
+ /**
31
+ * Inserts the given script contents into the HTML document and returns a new source with the modified content.
32
+ *
33
+ * @param {Object} options - The options object.
34
+ * @param {string} options.originalSource - The original HTML source.
35
+ * @param {Object} options.scriptContents - The contents of the script to be inserted.
36
+ * @return {sources.ReplaceSource} The new source with the modified HTML content.
37
+ */
38
+ function insertScriptContentsIntoDocument({
39
+ originalSource,
40
+ scriptContents,
41
+ }) {
42
+ // parse file as html document
43
+ const document = parse5.parse(originalSource, {
44
+ sourceCodeLocationInfo: true,
45
+ });
46
+
47
+ // find the body element
48
+ const scriptInsertionPoint = findScriptInsertionPoint({
49
+ document,
50
+ originalSource,
51
+ });
52
+
53
+ // create Paragon script to inject into the HTML document
54
+ const paragonScript = `<script type="text/javascript">var PARAGON_THEME = ${JSON.stringify(scriptContents, null, 2)};</script>`;
55
+
56
+ // insert the Paragon script into the HTML document
57
+ const newSource = new sources.ReplaceSource(
58
+ new sources.RawSource(originalSource),
59
+ 'index.html',
60
+ );
61
+ newSource.insert(scriptInsertionPoint, minifyScript(paragonScript));
62
+ return newSource;
63
+ }
64
+
65
+ /**
66
+ * Creates an object with the provided version, defaults, coreCssAsset, and themeVariantCssAssets
67
+ * and returns it. The returned object has the following structure:
68
+ * {
69
+ * version: The provided version,
70
+ * themeUrls: {
71
+ * core: The provided coreCssAsset,
72
+ * variants: The provided themeVariantCssAssets,
73
+ * defaults: The provided defaults
74
+ * }
75
+ * }
76
+ *
77
+ * @param {Object} options - The options object.
78
+ * @param {string} options.version - The version to be added to the returned object.
79
+ * @param {Object} options.defaults - The defaults to be added to the returned object.
80
+ * @param {Object} options.coreCssAsset - The coreCssAsset to be added to the returned object.
81
+ * @param {Object} options.themeVariantCssAssets - The themeVariantCssAssets to be added to the returned object.
82
+ * @return {Object} The object with the provided version, defaults, coreCssAsset, and themeVariantCssAssets.
83
+ */
84
+ function addToScriptContents({
85
+ version,
86
+ defaults,
87
+ coreCssAsset,
88
+ themeVariantCssAssets,
89
+ }) {
90
+ return {
91
+ version,
92
+ themeUrls: {
93
+ core: coreCssAsset,
94
+ variants: themeVariantCssAssets,
95
+ defaults,
96
+ },
97
+ };
98
+ }
99
+
100
+ /**
101
+ * Generates the script contents object based on the provided assets and versions.
102
+ *
103
+ * @param {Object} options - The options object.
104
+ * @param {Object} options.paragonCoreCssAsset - The asset for the Paragon core CSS.
105
+ * @param {Object} options.paragonThemeVariantCssAssets - The assets for the Paragon theme variants.
106
+ * @param {Object} options.brandCoreCssAsset - The asset for the brand core CSS.
107
+ * @param {Object} options.brandThemeVariantCssAssets - The assets for the brand theme variants.
108
+ * @param {Object} options.paragonThemeCss - The Paragon theme CSS.
109
+ * @param {string} options.paragonVersion - The version of the Paragon theme.
110
+ * @param {Object} options.brandThemeCss - The brand theme CSS.
111
+ * @param {string} options.brandVersion - The version of the brand theme.
112
+ * @return {Object} The script contents object.
113
+ */
114
+ function generateScriptContents({
115
+ paragonCoreCssAsset,
116
+ paragonThemeVariantCssAssets,
117
+ brandCoreCssAsset,
118
+ brandThemeVariantCssAssets,
119
+ paragonThemeCss,
120
+ paragonVersion,
121
+ brandThemeCss,
122
+ brandVersion,
123
+ }) {
124
+ const scriptContents = {};
125
+ scriptContents.paragon = addToScriptContents({
126
+ version: paragonVersion,
127
+ coreCssAsset: paragonCoreCssAsset,
128
+ themeVariantCssAssets: paragonThemeVariantCssAssets,
129
+ defaults: paragonThemeCss?.defaults,
130
+ });
131
+ scriptContents.brand = addToScriptContents({
132
+ version: brandVersion,
133
+ coreCssAsset: brandCoreCssAsset,
134
+ themeVariantCssAssets: brandThemeVariantCssAssets,
135
+ defaults: brandThemeCss?.defaults,
136
+ });
137
+ return scriptContents;
138
+ }
139
+
140
+ module.exports = {
141
+ addToScriptContents,
142
+ insertScriptContentsIntoDocument,
143
+ generateScriptContents,
144
+ };
@@ -0,0 +1,107 @@
1
+ const parse5 = require('parse5');
2
+ const { sources } = require('webpack');
3
+
4
+ const { getDescendantByTag } = require('./tagUtils');
5
+
6
+ /**
7
+ * Finds the insertion point for a stylesheet in an HTML document.
8
+ *
9
+ * @param {Object} options - The options object.
10
+ * @param {Object} options.document - The parsed HTML document.
11
+ * @param {string} options.source - The original source code of the HTML document.
12
+ * @throws {Error} If the head element is missing in the HTML document.
13
+ * @return {number} The insertion point for the stylesheet in the HTML document.
14
+ */
15
+ function findStylesheetInsertionPoint({ document, source }) {
16
+ const headElement = getDescendantByTag(document, 'head');
17
+ if (!headElement) {
18
+ throw new Error('Missing head element in index.html.');
19
+ }
20
+
21
+ // determine script insertion point
22
+ if (headElement.sourceCodeLocation?.startTag) {
23
+ return headElement.sourceCodeLocation.startTag.endOffset;
24
+ }
25
+
26
+ // less accurate fallback
27
+ const headTagString = '<head>';
28
+ const headTagIndex = source.indexOf(headTagString);
29
+ return headTagIndex + headTagString.length;
30
+ }
31
+
32
+ /**
33
+ * Inserts stylesheets into an HTML document.
34
+ *
35
+ * @param {object} options - The options for inserting stylesheets.
36
+ * @param {string} options.source - The HTML source code.
37
+ * @param {object} options.urls - The URLs of the stylesheets to be inserted.
38
+ * @param {string} options.urls.default - The URL of the default stylesheet.
39
+ * @param {string} options.urls.brandOverride - The URL of the brand override stylesheet.
40
+ * @return {object} The new source code with the stylesheets inserted.
41
+ */
42
+ function insertStylesheetsIntoDocument({
43
+ source,
44
+ urls,
45
+ }) {
46
+ // parse file as html document
47
+ const document = parse5.parse(source, {
48
+ sourceCodeLocationInfo: true,
49
+ });
50
+ if (!getDescendantByTag(document, 'head')) {
51
+ return undefined;
52
+ }
53
+
54
+ const newSource = new sources.ReplaceSource(
55
+ new sources.RawSource(source),
56
+ 'index.html',
57
+ );
58
+
59
+ // insert the brand overrides styles into the HTML document
60
+ const stylesheetInsertionPoint = findStylesheetInsertionPoint({
61
+ document,
62
+ source: newSource,
63
+ });
64
+
65
+ /**
66
+ * Creates a new stylesheet link element.
67
+ *
68
+ * @param {string} url - The URL of the stylesheet.
69
+ * @return {string} The HTML code for the stylesheet link element.
70
+ */
71
+ function createNewStylesheet(url) {
72
+ const baseLink = `<link
73
+ type="text/css"
74
+ rel="preload"
75
+ as="style"
76
+ href="${url}"
77
+ onload="this.rel='stylesheet';"
78
+ onerror="this.remove();"
79
+ />`;
80
+ return baseLink;
81
+ }
82
+
83
+ if (urls.default) {
84
+ const existingDefaultLink = getDescendantByTag(`link[href='${urls.default}']`);
85
+ if (!existingDefaultLink) {
86
+ // create link to inject into the HTML document
87
+ const stylesheetLink = createNewStylesheet(urls.default);
88
+ newSource.insert(stylesheetInsertionPoint, stylesheetLink);
89
+ }
90
+ }
91
+
92
+ if (urls.brandOverride) {
93
+ const existingBrandLink = getDescendantByTag(`link[href='${urls.brandOverride}']`);
94
+ if (!existingBrandLink) {
95
+ // create link to inject into the HTML document
96
+ const stylesheetLink = createNewStylesheet(urls.brandOverride);
97
+ newSource.insert(stylesheetInsertionPoint, stylesheetLink);
98
+ }
99
+ }
100
+
101
+ return newSource;
102
+ }
103
+
104
+ module.exports = {
105
+ findStylesheetInsertionPoint,
106
+ insertStylesheetsIntoDocument,
107
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Recursively searches for a descendant node with the specified tag name.
3
+ *
4
+ * @param {Object} node - The root node to start the search from.
5
+ * @param {string} tag - The tag name to search for.
6
+ * @return {Object|null} The first descendant node with the specified tag name, or null if not found.
7
+ */
8
+ function getDescendantByTag(node, tag) {
9
+ for (let i = 0; i < node.childNodes?.length; i++) {
10
+ if (node.childNodes[i].tagName === tag) {
11
+ return node.childNodes[i];
12
+ }
13
+ const result = getDescendantByTag(node.childNodes[i], tag);
14
+ if (result) {
15
+ return result;
16
+ }
17
+ }
18
+ return null;
19
+ }
20
+
21
+ /**
22
+ * Replaces a wildcard keyword in a URL with a local version.
23
+ *
24
+ * @param {Object} options - The options object.
25
+ * @param {string} options.url - The URL to substitute the keyword in.
26
+ * @param {string} options.wildcardKeyword - The wildcard keyword to replace.
27
+ * @param {string} options.localVersion - The local version to substitute the keyword with.
28
+ * @return {string} The URL with the wildcard keyword substituted with the local version,
29
+ * or the original URL if no substitution is needed.
30
+ */
31
+ function handleVersionSubstitution({ url, wildcardKeyword, localVersion }) {
32
+ if (!url || !url.includes(wildcardKeyword) || !localVersion) {
33
+ return url;
34
+ }
35
+ return url.replaceAll(wildcardKeyword, localVersion);
36
+ }
37
+
38
+ /**
39
+ * Minifies a script by removing unnecessary whitespace and line breaks.
40
+ *
41
+ * @param {string} script - The script to be minified.
42
+ * @return {string} The minified script.
43
+ */
44
+ function minifyScript(script) {
45
+ return script
46
+ .replace(/>[\r\n ]+</g, '><')
47
+ .replace(/(<.*?>)|\s+/g, (m, $1) => {
48
+ if ($1) { return $1; }
49
+ return ' ';
50
+ })
51
+ .trim();
52
+ }
53
+
54
+ module.exports = {
55
+ getDescendantByTag,
56
+ handleVersionSubstitution,
57
+ minifyScript,
58
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openedx/frontend-build",
3
- "version": "15.0.0-alpha.2",
3
+ "version": "15.0.0-alpha.20",
4
4
  "description": "Build tools, setup and config for frontend apps",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -13,6 +13,12 @@
13
13
  "lint": "eslint . --no-eslintrc -c .eslintrc.js",
14
14
  "test": "bash ./smoke-test.sh"
15
15
  },
16
+ "files": [
17
+ "/bin",
18
+ "/config",
19
+ "/lib",
20
+ "tsconfig.json"
21
+ ],
16
22
  "repository": {
17
23
  "type": "git",
18
24
  "url": "git+https://github.com/openedx/frontend-build.git"
@@ -25,25 +31,25 @@
25
31
  },
26
32
  "homepage": "https://github.com/openedx/frontend-build#readme",
27
33
  "dependencies": {
28
- "@babel/cli": "7.22.5",
29
- "@babel/core": "7.22.5",
34
+ "@babel/cli": "7.24.8",
35
+ "@babel/core": "7.24.9",
30
36
  "@babel/eslint-parser": "7.22.9",
31
37
  "@babel/plugin-proposal-class-properties": "7.18.6",
32
38
  "@babel/plugin-proposal-object-rest-spread": "7.20.7",
33
39
  "@babel/plugin-syntax-dynamic-import": "7.8.3",
34
- "@babel/preset-env": "7.22.5",
35
- "@babel/preset-react": "7.22.5",
36
- "@edx/eslint-config": "4.0.0",
40
+ "@babel/preset-env": "7.24.8",
41
+ "@babel/preset-react": "7.24.7",
42
+ "@edx/eslint-config": "4.2.0",
37
43
  "@edx/new-relic-source-map-webpack-plugin": "2.1.0",
38
- "@edx/typescript-config": "1.0.1",
44
+ "@edx/typescript-config": "1.1.0",
39
45
  "@formatjs/cli": "^6.0.3",
40
46
  "@fullhuman/postcss-purgecss": "5.0.0",
41
- "@pmmmwh/react-refresh-webpack-plugin": "0.5.11",
47
+ "@pmmmwh/react-refresh-webpack-plugin": "0.5.15",
42
48
  "@svgr/webpack": "8.1.0",
43
49
  "@types/jest": "29.5.12",
44
50
  "@typescript-eslint/eslint-plugin": "^5.58.0",
45
51
  "@typescript-eslint/parser": "^5.58.0",
46
- "autoprefixer": "10.4.19",
52
+ "autoprefixer": "10.4.20",
47
53
  "babel-jest": "29.6.1",
48
54
  "babel-loader": "9.1.3",
49
55
  "babel-plugin-formatjs": "^10.4.0",
@@ -71,26 +77,28 @@
71
77
  "jest": "29.6.1",
72
78
  "jest-environment-jsdom": "29.6.1",
73
79
  "mini-css-extract-plugin": "1.6.2",
74
- "postcss": "8.4.38",
75
- "postcss-custom-media": "10.0.4",
80
+ "parse5": "7.1.2",
81
+ "postcss": "8.4.47",
82
+ "postcss-custom-media": "10.0.8",
76
83
  "postcss-loader": "7.3.4",
77
84
  "postcss-rtlcss": "5.1.2",
78
85
  "react-dev-utils": "12.0.1",
79
- "react-refresh": "0.14.0",
86
+ "react-refresh": "0.14.2",
80
87
  "resolve-url-loader": "5.0.0",
81
88
  "sass": "1.69.7",
82
89
  "sass-loader": "13.3.3",
83
90
  "sharp": "0.32.6",
84
91
  "source-map-loader": "4.0.2",
85
92
  "style-loader": "3.3.4",
86
- "ts-jest": "29.1.2",
93
+ "ts-jest": "29.1.4",
87
94
  "typescript": "4.9.5",
88
95
  "url-loader": "4.1.1",
89
96
  "webpack": "^5.89.0",
90
97
  "webpack-bundle-analyzer": "^4.10.1",
91
98
  "webpack-cli": "^5.1.4",
92
99
  "webpack-dev-server": "^4.15.1",
93
- "webpack-merge": "^5.10.0"
100
+ "webpack-merge": "^5.10.0",
101
+ "webpack-remove-empty-scripts": "1.0.4"
94
102
  },
95
103
  "devDependencies": {
96
104
  "@babel/preset-typescript": "^7.18.6",
package/.eslintignore DELETED
@@ -1,5 +0,0 @@
1
- coverage/*
2
- dist/
3
- node_modules/
4
- __mocks__/
5
- __snapshots__/
package/.eslintrc.js DELETED
@@ -1,10 +0,0 @@
1
- const { createConfig } = require('.');
2
-
3
- module.exports = createConfig('eslint', {
4
- rules: {
5
- 'no-console': 'off',
6
- 'import/no-dynamic-require': 'off',
7
- 'global-require': 'off',
8
- 'no-template-curly-in-string': 'off',
9
- },
10
- });
@@ -1,19 +0,0 @@
1
- # Run the workflow that adds new tickets that are either:
2
- # - labelled "DEPR"
3
- # - title starts with "[DEPR]"
4
- # - body starts with "Proposal Date" (this is the first template field)
5
- # to the org-wide DEPR project board
6
-
7
- name: Add newly created DEPR issues to the DEPR project board
8
-
9
- on:
10
- issues:
11
- types: [opened]
12
-
13
- jobs:
14
- routeissue:
15
- uses: openedx/.github/.github/workflows/add-depr-ticket-to-depr-board.yml@master
16
- secrets:
17
- GITHUB_APP_ID: ${{ secrets.GRAPHQL_AUTH_APP_ID }}
18
- GITHUB_APP_PRIVATE_KEY: ${{ secrets.GRAPHQL_AUTH_APP_PEM }}
19
- SLACK_BOT_TOKEN: ${{ secrets.SLACK_ISSUE_BOT_TOKEN }}
@@ -1,20 +0,0 @@
1
- # This workflow runs when a comment is made on the ticket
2
- # If the comment starts with "label: " it tries to apply
3
- # the label indicated in rest of comment.
4
- # If the comment starts with "remove label: ", it tries
5
- # to remove the indicated label.
6
- # Note: Labels are allowed to have spaces and this script does
7
- # not parse spaces (as often a space is legitimate), so the command
8
- # "label: really long lots of words label" will apply the
9
- # label "really long lots of words label"
10
-
11
- name: Allows for the adding and removing of labels via comment
12
-
13
- on:
14
- issue_comment:
15
- types: [created]
16
-
17
- jobs:
18
- add_remove_labels:
19
- uses: openedx/.github/.github/workflows/add-remove-label-on-comment.yml@master
20
-
@@ -1,30 +0,0 @@
1
- name: Default CI
2
- on:
3
- push:
4
- branches:
5
- - master
6
- pull_request:
7
- branches:
8
- - '**'
9
- jobs:
10
- tests:
11
- runs-on: ubuntu-latest
12
- steps:
13
- - name: Checkout
14
- uses: actions/checkout@v4
15
- with:
16
- fetch-depth: 0
17
- - name: Setup Nodejs Env
18
- run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
19
- - name: Setup Nodejs
20
- uses: actions/setup-node@v4
21
- with:
22
- node-version: ${{ env.NODE_VER }}
23
- - name: Install dependencies
24
- run: npm ci
25
- - name: Lint
26
- run: npm run lint
27
- - name: Test
28
- run: npm run test
29
- - name: Upload coverage to Codecov
30
- uses: codecov/codecov-action@v3