@openedx/frontend-base 1.0.0-alpha.0

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 (356) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +112 -0
  3. package/config/babel/babel.config.js +28 -0
  4. package/config/config-helpers/createConfig.js +13 -0
  5. package/config/config-helpers/createLintConfig.js +16 -0
  6. package/config/config-helpers/getBaseConfig.js +12 -0
  7. package/config/defaultConfigPaths.js +35 -0
  8. package/config/eslint/base.eslint.config.js +113 -0
  9. package/config/index.js +12 -0
  10. package/config/jest/jest.config.js +30 -0
  11. package/config/tsconfig.json +32 -0
  12. package/config/types.js +25 -0
  13. package/config/webpack/common-config/all/getCodeRules.js +52 -0
  14. package/config/webpack/common-config/all/getFileLoaderRules.js +26 -0
  15. package/config/webpack/common-config/all/getIgnoreWarnings.js +14 -0
  16. package/config/webpack/common-config/all/getImageMinimizer.js +25 -0
  17. package/config/webpack/common-config/all/getStylesheetRule.js +112 -0
  18. package/config/webpack/common-config/dev/getDevServer.js +38 -0
  19. package/config/webpack/common-config/index.js +18 -0
  20. package/config/webpack/common-config/site/getHtmlWebpackPlugin.js +16 -0
  21. package/config/webpack/plugins/html-webpack-new-relic-plugin/HtmlWebpackNewRelicPlugin.js +91 -0
  22. package/config/webpack/plugins/html-webpack-new-relic-plugin/index.js +7 -0
  23. package/config/webpack/plugins/html-webpack-new-relic-plugin/test/fixtures/entry.js +3 -0
  24. package/config/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.js +108 -0
  25. package/config/webpack/plugins/paragon-webpack-plugin/index.js +7 -0
  26. package/config/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.js +64 -0
  27. package/config/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.js +53 -0
  28. package/config/webpack/plugins/paragon-webpack-plugin/utils/index.js +9 -0
  29. package/config/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.js +114 -0
  30. package/config/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.js +146 -0
  31. package/config/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.js +126 -0
  32. package/config/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.js +57 -0
  33. package/config/webpack/types.js +2 -0
  34. package/config/webpack/utils/getLocalAliases.js +65 -0
  35. package/config/webpack/utils/getPublicPath.js +6 -0
  36. package/config/webpack/utils/getResolvedSiteConfigPath.js +32 -0
  37. package/config/webpack/utils/paragonUtils.js +138 -0
  38. package/config/webpack/webpack.config.build.js +80 -0
  39. package/config/webpack/webpack.config.dev.js +76 -0
  40. package/config/webpack/webpack.config.dev.shell.js +110 -0
  41. package/eslint.config.js +18 -0
  42. package/frontend-base.d.ts +8 -0
  43. package/index.ts +7 -0
  44. package/jest.config.js +7 -0
  45. package/openedx-frontend-base.tgz +0 -0
  46. package/package.json +149 -0
  47. package/runtime/analytics/MockAnalyticsService.js +71 -0
  48. package/runtime/analytics/SegmentAnalyticsService.js +243 -0
  49. package/runtime/analytics/index.ts +12 -0
  50. package/runtime/analytics/interface.js +145 -0
  51. package/runtime/auth/AxiosCsrfTokenService.js +60 -0
  52. package/runtime/auth/AxiosJwtAuthService.js +363 -0
  53. package/runtime/auth/AxiosJwtTokenService.js +134 -0
  54. package/runtime/auth/LocalForageCache.js +76 -0
  55. package/runtime/auth/MockAuthService.js +278 -0
  56. package/runtime/auth/index.ts +19 -0
  57. package/runtime/auth/interceptors/createCsrfTokenProviderInterceptor.js +36 -0
  58. package/runtime/auth/interceptors/createJwtTokenProviderInterceptor.js +37 -0
  59. package/runtime/auth/interceptors/createProcessAxiosRequestErrorInterceptor.js +20 -0
  60. package/runtime/auth/interceptors/createRetryInterceptor.js +74 -0
  61. package/runtime/auth/interface.js +309 -0
  62. package/runtime/auth/utils.js +105 -0
  63. package/runtime/babel.config.js +3 -0
  64. package/runtime/config/index.ts +295 -0
  65. package/runtime/constants.ts +68 -0
  66. package/runtime/i18n/index.js +118 -0
  67. package/runtime/i18n/injectIntlWithShim.jsx +48 -0
  68. package/runtime/i18n/lib.ts +272 -0
  69. package/runtime/index.ts +134 -0
  70. package/runtime/initialize.js +352 -0
  71. package/runtime/jest.config.js +32 -0
  72. package/runtime/logging/MockLoggingService.js +31 -0
  73. package/runtime/logging/NewRelicLoggingService.js +184 -0
  74. package/runtime/logging/index.ts +9 -0
  75. package/runtime/logging/interface.js +109 -0
  76. package/runtime/logging/types.ts +4 -0
  77. package/runtime/react/AuthenticatedPageRoute.jsx +43 -0
  78. package/runtime/react/CombinedAppProvider.tsx +46 -0
  79. package/runtime/react/CurrentAppContext.tsx +25 -0
  80. package/runtime/react/CurrentAppProvider.tsx +46 -0
  81. package/runtime/react/Divider.tsx +5 -0
  82. package/runtime/react/ErrorBoundary.jsx +47 -0
  83. package/runtime/react/ErrorPage.jsx +72 -0
  84. package/runtime/react/LoginRedirect.jsx +16 -0
  85. package/runtime/react/PageWrap.jsx +24 -0
  86. package/runtime/react/SiteContext.tsx +32 -0
  87. package/runtime/react/SiteProvider.tsx +78 -0
  88. package/runtime/react/hooks.ts +106 -0
  89. package/runtime/react/index.ts +19 -0
  90. package/runtime/routing/index.ts +1 -0
  91. package/runtime/routing/utils.ts +34 -0
  92. package/runtime/scripts/GoogleAnalyticsLoader.ts +59 -0
  93. package/runtime/scripts/index.ts +1 -0
  94. package/runtime/setupTest.js +49 -0
  95. package/runtime/slots/Slot.tsx +32 -0
  96. package/runtime/slots/SlotContext.tsx +8 -0
  97. package/runtime/slots/hooks.ts +35 -0
  98. package/runtime/slots/index.ts +7 -0
  99. package/runtime/slots/layout/DefaultSlotLayout.tsx +9 -0
  100. package/runtime/slots/layout/hooks.ts +65 -0
  101. package/runtime/slots/layout/index.ts +5 -0
  102. package/runtime/slots/layout/types.ts +45 -0
  103. package/runtime/slots/layout/utils.ts +14 -0
  104. package/runtime/slots/types.ts +23 -0
  105. package/runtime/slots/utils.ts +59 -0
  106. package/runtime/slots/widget/WidgetContext.tsx +9 -0
  107. package/runtime/slots/widget/WidgetProvider.tsx +30 -0
  108. package/runtime/slots/widget/hooks.ts +105 -0
  109. package/runtime/slots/widget/iframe/IFrameContentWrapper.messages.tsx +16 -0
  110. package/runtime/slots/widget/iframe/IFrameContentWrapper.tsx +84 -0
  111. package/runtime/slots/widget/iframe/IFrameWidget.tsx +59 -0
  112. package/runtime/slots/widget/iframe/constants.ts +19 -0
  113. package/runtime/slots/widget/iframe/hooks.ts +179 -0
  114. package/runtime/slots/widget/iframe/index.ts +6 -0
  115. package/runtime/slots/widget/iframe/types.ts +7 -0
  116. package/runtime/slots/widget/index.ts +6 -0
  117. package/runtime/slots/widget/types.ts +134 -0
  118. package/runtime/slots/widget/utils.tsx +201 -0
  119. package/runtime/subscriptions.ts +60 -0
  120. package/runtime/testing/index.ts +9 -0
  121. package/runtime/testing/initializeMockApp.ts +81 -0
  122. package/runtime/testing/mockMessages.ts +23 -0
  123. package/runtime/utils.js +178 -0
  124. package/shell/DefaultLayout.tsx +18 -0
  125. package/shell/DefaultMain.tsx +7 -0
  126. package/shell/Logo.tsx +28 -0
  127. package/shell/Shell.messages.ts +61 -0
  128. package/shell/Shell.tsx +18 -0
  129. package/shell/app.scss +149 -0
  130. package/shell/app.ts +24 -0
  131. package/shell/babel.config.js +3 -0
  132. package/shell/dev/devFooter/app.tsx +43 -0
  133. package/shell/dev/devFooter/index.ts +1 -0
  134. package/shell/dev/devHeader/BarContext.tsx +13 -0
  135. package/shell/dev/devHeader/BarLink.tsx +16 -0
  136. package/shell/dev/devHeader/BarProvider.tsx +25 -0
  137. package/shell/dev/devHeader/CoursesLink.tsx +16 -0
  138. package/shell/dev/devHeader/FooContext.tsx +13 -0
  139. package/shell/dev/devHeader/FooLink.tsx +16 -0
  140. package/shell/dev/devHeader/FooProvider.tsx +25 -0
  141. package/shell/dev/devHeader/app.tsx +53 -0
  142. package/shell/dev/devHeader/index.ts +1 -0
  143. package/shell/dev/devHeader/providers.tsx +11 -0
  144. package/shell/dev/devHome/HomePage.tsx +28 -0
  145. package/shell/dev/devHome/app.ts +18 -0
  146. package/shell/dev/devHome/i18n/index.ts +27 -0
  147. package/shell/dev/devHome/index.ts +1 -0
  148. package/shell/dev/devHome/messages.ts +11 -0
  149. package/shell/dev/devUser/app.tsx +24 -0
  150. package/shell/dev/devUser/index.ts +1 -0
  151. package/shell/dev/index.ts +5 -0
  152. package/shell/dev/slotShowcase/HorizontalSlotLayout.tsx +11 -0
  153. package/shell/dev/slotShowcase/LayoutWithOptions.tsx +17 -0
  154. package/shell/dev/slotShowcase/SlotShowcasePage.tsx +66 -0
  155. package/shell/dev/slotShowcase/WidgetWithOptions.tsx +11 -0
  156. package/shell/dev/slotShowcase/app.tsx +373 -0
  157. package/shell/dev/slotShowcase/index.ts +1 -0
  158. package/shell/footer/CenterLinks.tsx +11 -0
  159. package/shell/footer/CopyrightNotice.tsx +36 -0
  160. package/shell/footer/Footer.tsx +34 -0
  161. package/shell/footer/LabeledLinkColumn.tsx +19 -0
  162. package/shell/footer/LanguageMenu.tsx +35 -0
  163. package/shell/footer/LanguageMenuItem.tsx +23 -0
  164. package/shell/footer/LeftLinks.tsx +11 -0
  165. package/shell/footer/LegalNotices.tsx +17 -0
  166. package/shell/footer/PoweredBy.tsx +17 -0
  167. package/shell/footer/RevealLinks.tsx +43 -0
  168. package/shell/footer/RightLinks.tsx +11 -0
  169. package/shell/footer/app.tsx +73 -0
  170. package/shell/footer/data/api.ts +48 -0
  171. package/shell/footer/index.ts +2 -0
  172. package/shell/header/AuthenticatedMenu.tsx +32 -0
  173. package/shell/header/Header.tsx +17 -0
  174. package/shell/header/anonymous-menu/AnonymousMenu.tsx +14 -0
  175. package/shell/header/anonymous-menu/LoginButton.tsx +14 -0
  176. package/shell/header/anonymous-menu/RegisterButton.tsx +15 -0
  177. package/shell/header/app.tsx +142 -0
  178. package/shell/header/desktop/DesktopLayout.tsx +22 -0
  179. package/shell/header/desktop/PrimaryNavLinks.tsx +10 -0
  180. package/shell/header/desktop/SecondaryNavLinks.tsx +10 -0
  181. package/shell/header/index.ts +2 -0
  182. package/shell/header/mobile/MobileLayout.tsx +47 -0
  183. package/shell/header/mobile/MobileNavLinks.tsx +10 -0
  184. package/shell/i18n/index.ts +25 -0
  185. package/shell/index.ts +7 -0
  186. package/shell/jest.config.js +30 -0
  187. package/shell/menus/LinkMenuItem.tsx +64 -0
  188. package/shell/menus/NavDropdownMenuSlot.tsx +29 -0
  189. package/shell/menus/ProfileLinkMenuItem.tsx +33 -0
  190. package/shell/menus/data/utils.ts +19 -0
  191. package/shell/public/index.html +10 -0
  192. package/shell/router/createRouter.ts +17 -0
  193. package/shell/router/getAppRoutes.ts +21 -0
  194. package/shell/setupTest.js +48 -0
  195. package/shell/site.config.dev.tsx +49 -0
  196. package/shell/site.tsx +41 -0
  197. package/test-site/app.d.ts +15 -0
  198. package/test-site/dist/176.436443549ebb858db483.js +2 -0
  199. package/test-site/dist/176.436443549ebb858db483.js.map +1 -0
  200. package/test-site/dist/362.536eff787d2380fe246c.js +2 -0
  201. package/test-site/dist/362.536eff787d2380fe246c.js.map +1 -0
  202. package/test-site/dist/653.486966b108d224551296.js +2 -0
  203. package/test-site/dist/653.486966b108d224551296.js.map +1 -0
  204. package/test-site/dist/74e025d3fe9a7b7f8503054e2563b353.jpg +0 -0
  205. package/test-site/dist/806.323cf6496ad0a7fe73a7.js +3 -0
  206. package/test-site/dist/806.323cf6496ad0a7fe73a7.js.LICENSE.txt +106 -0
  207. package/test-site/dist/806.323cf6496ad0a7fe73a7.js.map +1 -0
  208. package/test-site/dist/95ec738c0b7faac5b5c9126794446bbd.svg +4 -0
  209. package/test-site/dist/app.612058b36c74787759ac.css +61 -0
  210. package/test-site/dist/app.612058b36c74787759ac.css.map +1 -0
  211. package/test-site/dist/app.612058b36c74787759ac.js +2 -0
  212. package/test-site/dist/app.612058b36c74787759ac.js.map +1 -0
  213. package/test-site/dist/cb28cdb1468c915e27e5cec9af64f22f.svg +1 -0
  214. package/test-site/dist/index.html +1 -0
  215. package/test-site/dist/report.html +39 -0
  216. package/test-site/dist/runtime.c7aeaf7b967496cb076f.js +2 -0
  217. package/test-site/dist/runtime.c7aeaf7b967496cb076f.js.map +1 -0
  218. package/test-site/eslint.config.js +12 -0
  219. package/test-site/package-lock.json +19226 -0
  220. package/test-site/package.json +29 -0
  221. package/test-site/public/index.html +10 -0
  222. package/test-site/site.config.build.tsx +27 -0
  223. package/test-site/site.config.dev.tsx +27 -0
  224. package/test-site/src/authenticated-page/AuthenticatedPage.tsx +18 -0
  225. package/test-site/src/authenticated-page/i18n/index.ts +27 -0
  226. package/test-site/src/authenticated-page/index.tsx +28 -0
  227. package/test-site/src/example-page/ExamplePage.tsx +79 -0
  228. package/test-site/src/example-page/Image.tsx +11 -0
  229. package/test-site/src/example-page/ParagonPreview.jsx +66 -0
  230. package/test-site/src/example-page/apple.jpg +0 -0
  231. package/test-site/src/example-page/apple.svg +1 -0
  232. package/test-site/src/example-page/index.ts +16 -0
  233. package/test-site/src/i18n/README.md +3 -0
  234. package/test-site/src/i18n/messages/frontend-app-sample/ar.json +4 -0
  235. package/test-site/src/i18n/messages/frontend-app-sample/eo.json +1 -0
  236. package/test-site/src/i18n/messages/frontend-app-sample/es_419.json +4 -0
  237. package/test-site/src/i18n/messages/frontend-component-emptylangs/ar.json +1 -0
  238. package/test-site/src/i18n/messages/frontend-component-singlelang/ar.json +3 -0
  239. package/test-site/src/iframe-widget/IframeWidget.tsx +14 -0
  240. package/test-site/src/iframe-widget/index.ts +16 -0
  241. package/test-site/src/index.tsx +3 -0
  242. package/test-site/src/messages.js +11 -0
  243. package/test-site/src/site.scss +11 -0
  244. package/test-site/tsconfig.json +14 -0
  245. package/tools/babel/babel.config.js +27 -0
  246. package/tools/babel.config.js +3 -0
  247. package/tools/cli/README.md +29 -0
  248. package/tools/cli/commands/pack.ts +9 -0
  249. package/tools/cli/commands/release.ts +27 -0
  250. package/tools/cli/commands/serve.ts +43 -0
  251. package/tools/cli/intl-imports.ts +274 -0
  252. package/tools/cli/openedx.ts +101 -0
  253. package/tools/cli/transifex-utils.ts +75 -0
  254. package/tools/cli/utils/ensureConfigFilenameOption.ts +40 -0
  255. package/tools/cli/utils/formatter.ts +10 -0
  256. package/tools/cli/utils/getResolvedConfigPath.ts +23 -0
  257. package/tools/cli/utils/prettyPrintTitle.ts +15 -0
  258. package/tools/cli/utils/printUsage.ts +53 -0
  259. package/tools/config-helpers/createConfig.ts +8 -0
  260. package/tools/config-helpers/createLintConfig.ts +14 -0
  261. package/tools/config-helpers/getBaseConfig.ts +11 -0
  262. package/tools/defaultConfigPaths.ts +30 -0
  263. package/tools/dist/babel/babel.config.js +28 -0
  264. package/tools/dist/cli/commands/pack.js +14 -0
  265. package/tools/dist/cli/commands/release.js +28 -0
  266. package/tools/dist/cli/commands/serve.js +44 -0
  267. package/tools/dist/cli/intl-imports.js +233 -0
  268. package/tools/dist/cli/openedx.js +100 -0
  269. package/tools/dist/cli/transifex-utils.js +68 -0
  270. package/tools/dist/cli/utils/ensureConfigFilenameOption.js +42 -0
  271. package/tools/dist/cli/utils/formatter.js +10 -0
  272. package/tools/dist/cli/utils/getResolvedConfigPath.js +28 -0
  273. package/tools/dist/cli/utils/prettyPrintTitle.js +17 -0
  274. package/tools/dist/cli/utils/printUsage.js +48 -0
  275. package/tools/dist/config-helpers/createConfig.js +13 -0
  276. package/tools/dist/config-helpers/createLintConfig.js +16 -0
  277. package/tools/dist/config-helpers/getBaseConfig.js +12 -0
  278. package/tools/dist/defaultConfigPaths.js +35 -0
  279. package/tools/dist/eslint/base.eslint.config.js +113 -0
  280. package/tools/dist/eslint.config.js +11 -0
  281. package/tools/dist/index.js +12 -0
  282. package/tools/dist/jest/jest.config.js +30 -0
  283. package/tools/dist/jest.config.js +20 -0
  284. package/tools/dist/types.js +25 -0
  285. package/tools/dist/typescript/tsconfig.json +32 -0
  286. package/tools/dist/webpack/common-config/all/getCodeRules.js +52 -0
  287. package/tools/dist/webpack/common-config/all/getFileLoaderRules.js +26 -0
  288. package/tools/dist/webpack/common-config/all/getIgnoreWarnings.js +14 -0
  289. package/tools/dist/webpack/common-config/all/getImageMinimizer.js +25 -0
  290. package/tools/dist/webpack/common-config/all/getStylesheetRule.js +112 -0
  291. package/tools/dist/webpack/common-config/dev/getDevServer.js +38 -0
  292. package/tools/dist/webpack/common-config/index.js +18 -0
  293. package/tools/dist/webpack/common-config/site/getHtmlWebpackPlugin.js +16 -0
  294. package/tools/dist/webpack/plugins/html-webpack-new-relic-plugin/HtmlWebpackNewRelicPlugin.js +91 -0
  295. package/tools/dist/webpack/plugins/html-webpack-new-relic-plugin/index.js +7 -0
  296. package/tools/dist/webpack/plugins/html-webpack-new-relic-plugin/test/fixtures/entry.js +3 -0
  297. package/tools/dist/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.js +108 -0
  298. package/tools/dist/webpack/plugins/paragon-webpack-plugin/index.js +7 -0
  299. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.js +64 -0
  300. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.js +53 -0
  301. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/index.js +9 -0
  302. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.js +114 -0
  303. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.js +146 -0
  304. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.js +126 -0
  305. package/tools/dist/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.js +57 -0
  306. package/tools/dist/webpack/types.js +2 -0
  307. package/tools/dist/webpack/utils/getLocalAliases.js +65 -0
  308. package/tools/dist/webpack/utils/getPublicPath.js +6 -0
  309. package/tools/dist/webpack/utils/getResolvedSiteConfigPath.js +32 -0
  310. package/tools/dist/webpack/utils/paragonUtils.js +138 -0
  311. package/tools/dist/webpack/webpack.config.build.js +80 -0
  312. package/tools/dist/webpack/webpack.config.dev.js +76 -0
  313. package/tools/dist/webpack/webpack.config.dev.shell.js +110 -0
  314. package/tools/eslint/base.eslint.config.js +124 -0
  315. package/tools/eslint/modules.d.ts +5 -0
  316. package/tools/eslint.config.js +15 -0
  317. package/tools/index.ts +3 -0
  318. package/tools/jest/jest.config.js +30 -0
  319. package/tools/jest.config.js +19 -0
  320. package/tools/tsconfig.json +24 -0
  321. package/tools/types.ts +21 -0
  322. package/tools/typescript/tsconfig.json +32 -0
  323. package/tools/webpack/common-config/README.md +15 -0
  324. package/tools/webpack/common-config/all/getCodeRules.ts +51 -0
  325. package/tools/webpack/common-config/all/getFileLoaderRules.ts +23 -0
  326. package/tools/webpack/common-config/all/getIgnoreWarnings.ts +13 -0
  327. package/tools/webpack/common-config/all/getImageMinimizer.ts +26 -0
  328. package/tools/webpack/common-config/all/getStylesheetRule.ts +111 -0
  329. package/tools/webpack/common-config/dev/getDevServer.ts +35 -0
  330. package/tools/webpack/common-config/index.ts +6 -0
  331. package/tools/webpack/common-config/site/getHtmlWebpackPlugin.ts +11 -0
  332. package/tools/webpack/modules.d.ts +6 -0
  333. package/tools/webpack/plugins/html-webpack-new-relic-plugin/HtmlWebpackNewRelicPlugin.ts +102 -0
  334. package/tools/webpack/plugins/html-webpack-new-relic-plugin/LICENSE +21 -0
  335. package/tools/webpack/plugins/html-webpack-new-relic-plugin/README.md +7 -0
  336. package/tools/webpack/plugins/html-webpack-new-relic-plugin/index.js +3 -0
  337. package/tools/webpack/plugins/html-webpack-new-relic-plugin/test/fixtures/entry.js +1 -0
  338. package/tools/webpack/plugins/paragon-webpack-plugin/ParagonWebpackPlugin.ts +134 -0
  339. package/tools/webpack/plugins/paragon-webpack-plugin/index.ts +3 -0
  340. package/tools/webpack/plugins/paragon-webpack-plugin/utils/assetUtils.ts +71 -0
  341. package/tools/webpack/plugins/paragon-webpack-plugin/utils/htmlUtils.ts +72 -0
  342. package/tools/webpack/plugins/paragon-webpack-plugin/utils/index.ts +6 -0
  343. package/tools/webpack/plugins/paragon-webpack-plugin/utils/paragonStylesheetUtils.ts +131 -0
  344. package/tools/webpack/plugins/paragon-webpack-plugin/utils/scriptUtils.ts +144 -0
  345. package/tools/webpack/plugins/paragon-webpack-plugin/utils/stylesheetUtils.ts +106 -0
  346. package/tools/webpack/plugins/paragon-webpack-plugin/utils/tagUtils.ts +54 -0
  347. package/tools/webpack/types.ts +69 -0
  348. package/tools/webpack/utils/getLocalAliases.ts +65 -0
  349. package/tools/webpack/utils/getPublicPath.ts +3 -0
  350. package/tools/webpack/utils/getResolvedSiteConfigPath.ts +28 -0
  351. package/tools/webpack/utils/paragonUtils.ts +152 -0
  352. package/tools/webpack/webpack.config.build.ts +93 -0
  353. package/tools/webpack/webpack.config.dev.shell.ts +122 -0
  354. package/tools/webpack/webpack.config.dev.ts +90 -0
  355. package/tsconfig.json +23 -0
  356. package/types.ts +99 -0
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "test-site",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "src/index.jsx",
6
+ "scripts": {
7
+ "build": "openedx build",
8
+ "lint": "openedx lint .",
9
+ "dev": "openedx dev",
10
+ "serve": "openedx serve"
11
+ },
12
+ "keywords": [],
13
+ "author": "Open edX Community",
14
+ "license": "AGPL-3.0",
15
+ "peerDependencies": {
16
+ "@openedx/frontend-base": "file:../openedx-frontend-base.tgz",
17
+ "@openedx/paragon": "^22.20.2",
18
+ "react": "^18.3.1",
19
+ "react-dom": "^18.3.1",
20
+ "react-router": "^6.26.1",
21
+ "react-router-dom": "^6.26.1"
22
+ },
23
+ "devDependencies": {
24
+ "@edx/browserslist-config": "^1.5.0"
25
+ },
26
+ "dependencies": {
27
+ "@edx/brand": "npm:@openedx/brand-openedx@^1.2.3"
28
+ }
29
+ }
@@ -0,0 +1,10 @@
1
+ <!doctype html>
2
+ <html lang="en-us">
3
+ <head>
4
+ <title>Test Site</title>
5
+ <link rel="shortcut icon" href="https://edx-cdn.org/v3/default/favicon.ico" type="image/x-icon" />
6
+ </head>
7
+ <body>
8
+ <div id="root"></div>
9
+ </body>
10
+ </html>
@@ -0,0 +1,27 @@
1
+ import { footerApp, headerApp, shellApp, EnvironmentTypes, SiteConfig } from '@openedx/frontend-base';
2
+
3
+ import { authenticatedPageConfig, examplePageConfig, iframeWidgetConfig } from './src';
4
+
5
+ import './src/site.scss';
6
+
7
+ const siteConfig: SiteConfig = {
8
+ siteId: 'test',
9
+ siteName: 'Test Site',
10
+ baseUrl: 'http://apps.local.openedx.io:8080',
11
+ lmsBaseUrl: 'http://local.openedx.io:8000',
12
+ loginUrl: 'http://local.openedx.io:8000/login',
13
+ logoutUrl: 'http://local.openedx.io:8000/logout',
14
+
15
+ environment: EnvironmentTypes.PRODUCTION,
16
+ mfeConfigApiUrl: 'http://apps.local.openedx.io:8080/api/mfe_config/v1',
17
+ apps: [
18
+ shellApp,
19
+ headerApp,
20
+ footerApp,
21
+ examplePageConfig,
22
+ authenticatedPageConfig,
23
+ iframeWidgetConfig,
24
+ ],
25
+ };
26
+
27
+ export default siteConfig;
@@ -0,0 +1,27 @@
1
+ import { footerApp, headerApp, shellApp, EnvironmentTypes, SiteConfig } from '@openedx/frontend-base';
2
+
3
+ import { authenticatedPageConfig, examplePageConfig, iframeWidgetConfig } from './src';
4
+
5
+ import './src/site.scss';
6
+
7
+ const siteConfig: SiteConfig = {
8
+ siteId: 'test',
9
+ siteName: 'Test Site',
10
+ baseUrl: 'http://apps.local.openedx.io:8080',
11
+ lmsBaseUrl: 'http://local.openedx.io:8000',
12
+ loginUrl: 'http://local.openedx.io:8000/login',
13
+ logoutUrl: 'http://local.openedx.io:8000/logout',
14
+
15
+ environment: EnvironmentTypes.DEVELOPMENT,
16
+ mfeConfigApiUrl: 'http://apps.local.openedx.io:8080/api/mfe_config/v1',
17
+ apps: [
18
+ shellApp,
19
+ headerApp,
20
+ footerApp,
21
+ examplePageConfig,
22
+ authenticatedPageConfig,
23
+ iframeWidgetConfig,
24
+ ],
25
+ };
26
+
27
+ export default siteConfig;
@@ -0,0 +1,18 @@
1
+ import { Link } from 'react-router-dom';
2
+
3
+ import { useAuthenticatedUser, useSiteConfig } from '@openedx/frontend-base';
4
+ import { FormattedMessage } from 'react-intl';
5
+
6
+ export default function AuthenticatedPage() {
7
+ const authenticatedUser = useAuthenticatedUser();
8
+ const config = useSiteConfig();
9
+
10
+ return (
11
+ <main className="p-3">
12
+ <h1>{config.siteName} authenticated page.</h1>
13
+ <FormattedMessage id="authenticated.page.content" defaultMessage="This is a localized message. Try it in French." description="This is a test message to prove localization works." />
14
+ <p>{authenticatedUser === null ? 'You are not authenticated.' : `Hi there, ${authenticatedUser.username}.`}</p>
15
+ <p>Visit <Link to="/">public page</Link>.</p>
16
+ </main>
17
+ );
18
+ }
@@ -0,0 +1,27 @@
1
+ // Placeholder be overridden by `make pull_translations`
2
+ export default {
3
+ ar: {},
4
+ 'zh-hk': {},
5
+ 'zh-cn': {},
6
+ uk: {},
7
+ 'tr-tr': {},
8
+ th: {},
9
+ te: {},
10
+ ru: {},
11
+ 'pt-pt': {},
12
+ 'pt-br': {},
13
+ 'it-it': {},
14
+ id: {},
15
+ hi: {},
16
+ he: {},
17
+ 'fr-ca': {
18
+ 'authenticated.page.content': 'This is a localized message in French.'
19
+ },
20
+ fa: {},
21
+ 'es-es': {},
22
+ 'es-419': {},
23
+ el: {},
24
+ 'de-de': {},
25
+ da: {},
26
+ bo: {},
27
+ };
@@ -0,0 +1,28 @@
1
+ import { App, LinkMenuItem, WidgetOperationTypes } from '@openedx/frontend-base';
2
+ import messages from './i18n';
3
+
4
+ const config: App = {
5
+ appId: 'test-authenticated-page-app',
6
+ routes: [{
7
+ path: '/authenticated',
8
+ lazy: async () => {
9
+ const { default: Component } = await import('./AuthenticatedPage');
10
+ return {
11
+ Component,
12
+ };
13
+ },
14
+ }],
15
+ slots: [
16
+ {
17
+ slotId: 'org.openedx.frontend.slot.header.primaryLinks.v1',
18
+ id: 'authenticatedPageLink',
19
+ op: WidgetOperationTypes.APPEND,
20
+ element: (
21
+ <LinkMenuItem label="Authy Page" url="/authenticated" variant="navLink" />
22
+ )
23
+ }
24
+ ],
25
+ messages,
26
+ };
27
+
28
+ export default config;
@@ -0,0 +1,79 @@
1
+ import {
2
+ getAuthenticatedUser,
3
+ getSiteConfig,
4
+ logInfo,
5
+ useAuthenticatedUser,
6
+ useSiteConfig,
7
+ useIntl
8
+ } from '@openedx/frontend-base';
9
+ import { Container } from '@openedx/paragon';
10
+ import { useEffect } from 'react';
11
+ import { Link } from 'react-router-dom';
12
+ import messages from '../messages';
13
+ import Image from './Image';
14
+ import ParagonPreview from './ParagonPreview';
15
+ import appleImg from './apple.jpg';
16
+ import appleUrl from './apple.svg';
17
+
18
+ function printTestResult(value) {
19
+ return value ? '✅' : '❌';
20
+ }
21
+
22
+ export default function ExamplePage() {
23
+ const config = useSiteConfig();
24
+ const authenticatedUser = useAuthenticatedUser();
25
+
26
+ const intl = useIntl();
27
+
28
+ useEffect(() => {
29
+ logInfo('The example page can log info, which means logging is configured correctly.');
30
+ }, []);
31
+
32
+ return (
33
+ <Container>
34
+ <h1>{config.siteName} test page</h1>
35
+
36
+ <h2>Links</h2>
37
+ <p>Visit <Link to="/authenticated">authenticated page</Link>.</p>
38
+ <p>Visit <Link to="/error">error page</Link>.</p>
39
+
40
+ <h2>Context Config Test</h2>
41
+ <p>Is context.config equal to getSiteConfig()? {printTestResult(config === getSiteConfig())}</p>
42
+ <p>Is context.authenticatedUser equal to getAuthenticatedUser()? {printTestResult(authenticatedUser === getAuthenticatedUser())}</p>
43
+
44
+ <h2>SCSS parsing tests</h2>
45
+ <p><span className="red-text">&quot;The Apples&quot;</span> should be red (<code>color: red;</code> via <code>.red-text</code> CSS class in SCSS stylesheet)</p>
46
+
47
+ <h2>TSX parsing tests</h2>
48
+ <Image src={appleUrl} alt="apple.svg displayed in Image.tsx" style={{ width: '10rem' }} />
49
+
50
+ <h2>SVG import test</h2>
51
+ <img src={appleUrl} alt="apple.svg displayed in <img> tag" style={{ width: '10rem' }} />
52
+
53
+ <h2>JPG import test</h2>
54
+ <p><img src={appleImg} alt="apple.jpg displayed in <img> tag" style={{ width: '10rem' }} /></p>
55
+ <p>Photo by Louis Hansel @shotsoflouis on Unsplash</p>
56
+
57
+ <h2>i18n formatMessage test</h2>
58
+ <p>{intl.formatMessage(messages['test-site.message'])}</p>
59
+
60
+ <h2>Authenticated User Test</h2>
61
+ {authenticatedUser !== null ? (
62
+ <div>
63
+ <p>Authenticated Username: <strong>{authenticatedUser.username}</strong></p>
64
+ <p>
65
+ Authenticated user&apos;s name:
66
+ <strong>{authenticatedUser.username}</strong>
67
+ (Only available if user account has been fetched)
68
+ </p>
69
+ </div>
70
+ ) : (
71
+ <p>Unauthenticated {printTestResult(authenticatedUser === null)}</p>
72
+ )}
73
+
74
+ <h2>Right-to-left language handling tests</h2>
75
+ <p className="text-align-right">I&apos;m aligned right, but left in RTL.</p>
76
+ <ParagonPreview />
77
+ </Container>
78
+ );
79
+ }
@@ -0,0 +1,11 @@
1
+ import { CSSProperties } from 'react';
2
+
3
+ interface ImageProps {
4
+ src: string,
5
+ alt?: string,
6
+ style?: CSSProperties,
7
+ }
8
+
9
+ const Image = ({ alt, ...rest }: ImageProps) => <img alt={alt} {...rest} />;
10
+
11
+ export default Image;
@@ -0,0 +1,66 @@
1
+ import { Button, Stack } from '@openedx/paragon';
2
+
3
+ const ParagonPreview = () => {
4
+ if (!PARAGON_THEME) {
5
+ return <p>Missing <code>PARAGON_THEME</code> global variable. Depending on configuration, this may be OK.</p>;
6
+ }
7
+ return (
8
+ <>
9
+ <h2>Paragon</h2>
10
+
11
+ <Stack gap={4.5}>
12
+ <div>
13
+ <h3>Component preview</h3>
14
+ <div className="px-3 py-2 bg-light-200">
15
+ <Button>Hello world</Button>
16
+ </div>
17
+ </div>
18
+ <div>
19
+ <h3>Exposed theme CSS files</h3>
20
+ <p>
21
+ <em>
22
+ Note: Depending on the versions of <code>@openedx/paragon</code> and/or <code>@edx/brand</code> installed,
23
+ it is expected that no exposed theme CSS assets be listed here.
24
+ </em>
25
+ </p>
26
+ <ul className="mb-0">
27
+ {PARAGON_THEME.paragon.themeUrls.core.fileName && (
28
+ <li>
29
+ <a href={`/${PARAGON_THEME.paragon.themeUrls.core.fileName}`} target="_blank" rel="noopener noreferrer">
30
+ {PARAGON_THEME.paragon.themeUrls.core.fileName}
31
+ </a>
32
+ </li>
33
+ )}
34
+ {PARAGON_THEME.paragon.themeUrls.variants.light?.fileName && (
35
+ <li>
36
+ <a href={`/${PARAGON_THEME.paragon.themeUrls.variants.light.fileName}`} target="_blank" rel="noopener noreferrer">
37
+ {PARAGON_THEME.paragon.themeUrls.variants.light.fileName}
38
+ </a>
39
+ </li>
40
+ )}
41
+ {PARAGON_THEME.brand.themeUrls.core.fileName && (
42
+ <li>
43
+ <a href={`/${PARAGON_THEME.brand.themeUrls.core.fileName}`} target="_blank" rel="noopener noreferrer">
44
+ {PARAGON_THEME.brand.themeUrls.core.fileName}
45
+ </a>
46
+ </li>
47
+ )}
48
+ {PARAGON_THEME.brand.themeUrls.variants.light?.fileName && (
49
+ <li>
50
+ <a href={`/${PARAGON_THEME.brand.themeUrls.variants.light.fileName}`} target="_blank" rel="noopener noreferrer">
51
+ {PARAGON_THEME.brand.themeUrls.variants.light.fileName}
52
+ </a>
53
+ </li>
54
+ )}
55
+ </ul>
56
+ </div>
57
+ <div>
58
+ <h3>Contents of <code>PARAGON_THEME</code> global variable</h3>
59
+ <pre>{JSON.stringify(PARAGON_THEME, null, 2)}</pre>
60
+ </div>
61
+ </Stack>
62
+ </>
63
+ );
64
+ };
65
+
66
+ export default ParagonPreview;
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" data-name="Слой 1" viewBox="0 0 100 125" x="0px" y="0px"><title>Безымянный-1</title><g><path d="M48.29173,20.91309c.44045,2.67407.81828,4.968,1.25786,7.63686a29.75307,29.75307,0,0,0,3.91278-.37779c2.38512-.53346,4.71271-1.32728,7.10142-1.83905.66415-.14232,1.45907.32571,2.194.51374-.51414.48731-.94651,1.22009-1.55542,1.4231a42.59057,42.59057,0,0,1-15.1772,2.408,20.86177,20.86177,0,0,1-11.07629-3.71148,2.81986,2.81986,0,0,1-.51721-.49108,1.71988,1.71988,0,0,1-.175-.42192c.86026-1.19467,1.8261-.49218,2.778-.1154a46.95591,46.95591,0,0,0,5.50622,2.10209c2.1421.54764,2.49613.11136,2.15817-2.0335-.15791-1.00211-.45371-1.98313-.69919-2.9707a2.10178,2.10178,0,0,0-2.20542-1.71675,16.69777,16.69777,0,0,0-8.17976,1.66586c-1.21465.59569-2.44545,1.79479-4.57394.26q.91125-.52011,1.8225-1.04022a19.5657,19.5657,0,0,1,8.76662-2.94536c3.64447-.18813,3.3542-.397,4.83215-3.62009A43.17637,43.17637,0,0,1,49.38579,8.1986,27.03146,27.03146,0,0,1,52.78013,4.7669c.88679-.82751,2.099-1.13929,2.86044-.14869a2.95022,2.95022,0,0,1,.25154,2.67767A17.62547,17.62547,0,0,1,52.64,11.07318a11.939,11.939,0,0,0-3.691,7.01548,9.58451,9.58451,0,0,0-.00957,1.43118c4.67257-.53271,8.678,1.549,12.91179,2.71,1.42367.39039,3.072-.10087,4.61592-.07659,7.75187.12182,15.0069,1.70433,20.62774,7.56383a16.18131,16.18131,0,0,1,2.4769,3.90158,33.47619,33.47619,0,0,1,3.61715,18.76,57.39218,57.39218,0,0,1-3.11865,15.24337c-2.93307,7.71726-6.35779,15.17206-13.49812,20.07157a43.38827,43.38827,0,0,1-12.24457,6.25692c-1.14482.33576-2.26435.75733-3.39644,1.13692-4.80036,1.60938-9.57586.76787-14.37288-.07461-3.17591-.55779-6.3808-.95626-9.57884-1.38046a29.929,29.929,0,0,1-10.19653-3.69123c-4.50508-2.4015-8.054-5.78138-11.4774-9.37706A25.717,25.717,0,0,1,8.50666,67.54893,80.91649,80.91649,0,0,1,6.94228,44.17515c.52046-5.42775,2.03161-10.59663,5.905-14.45175,2.29913-2.28824,5.55312-3.65369,8.46933-5.26865a12.9111,12.9111,0,0,1,4.2301-1.42657c.71509-.1093,1.55884.62326,2.34436.97484a7.64709,7.64709,0,0,1-1.97233,1.10934c-4.79315,1.02586-9.26319,2.8239-12.29393,6.77242a24.38788,24.38788,0,0,0-4.743,13.48973,78.54727,78.54727,0,0,0,.41718,16.10944c1.07008,7.83658,3.75794,14.71927,10.052,20.00759a65.57961,65.57961,0,0,0,10.197,7.57349c4.09212,2.26826,8.61029,2.83369,13.1209,3.43065,3.11373.41208,6.235.427,9.37842,1.052,2.95178.58686,6.32407-.08449,9.33969-.86514A43.9325,43.9325,0,0,0,75.82337,85.6054a23.05284,23.05284,0,0,0,8.21682-10.00235c1.84358-4.47166,3.65114-8.96041,5.35771-13.48574,1.72782-4.58158,1.36369-9.43433,1.628-14.20465.26085-4.70673-1.32794-8.91356-3.338-13.02592-2.8196-5.76882-7.84365-8.5485-13.77934-9.91386a63.14758,63.14758,0,0,0-7.30061-.85715c-.29677-.03236-.66318-.13762-.88784-.01256-3.43263,1.91081-6.27313-.39109-9.33231-1.23972C53.881,22.16813,51.32861,21.63726,48.29173,20.91309Z"/><path d="M18.80551,79.4219A93.68635,93.68635,0,0,1,14.374,70.982c-2.23379-5.47935-2.67758-11.37723-3.2698-17.1937-.46425-4.55984.35623-9.05636,1.40022-13.49426a1.91994,1.91994,0,0,1,.54725-1.10293,5.32017,5.32017,0,0,1,1.50175-.48028c.06886.48819.37168,1.12159.17205,1.44313-3.97083,6.39657-2.75908,13.27394-2.04558,20.14746a39.84049,39.84049,0,0,0,4.424,14.10224c.79439,1.55454,1.70279,3.05071,2.5591,4.57359Q19.23423,79.19954,18.80551,79.4219Z"/><path d="M71.06622,81.56681c-1.856,2.46258-3.67635,4.95383-5.60617,7.35713-.29422.36637-1.09582.32535-1.66274.47277.11409-.534.05832-1.21408.37081-1.5775,1.6291-1.89438,3.327-3.73212,5.05971-5.533a7.53926,7.53926,0,0,1,1.615-.99912Z"/><path d="M64.62508,58.93776q-.52275,5.53883-1.04549,11.07761l-.56253-.02587c.04734-.932.14044-1.8643.13306-2.79584-.01888-2.38011-.12981-4.76066-.091-7.13914.00834-.51317.49166-1.01857.75619-1.52757Z"/><path d="M16.30692,54.97435c-.11374-.165-.33251-.33506-.33708-.51076-.08414-3.19571-.15835-6.392-.18637-9.58855a2.17449,2.17449,0,0,1,.44159-1.14816.8251.8251,0,0,1,.7359-.271.78393.78393,0,0,1,.38091.67113c-1.24846,3.49986-1.023,7.10006-.7936,10.70382C16.54985,54.8553,16.4593,54.88569,16.30692,54.97435Z"/><path d="M73.75838,52.91472c-.48393-1.65238-1.01168-3.29426-1.409-4.96718-.06771-.28473.42368-.70226.65677-1.05845.35052.25786.97181.48331,1.0072.77894.205,1.71337.272,3.44317.38582,5.16743Z"/><path d="M53.80963,71.39829l.79387-7.98009.47277.04527c.72984,2.75575-.035,5.37953-.74609,8.008Z"/><path d="M50.79682,89.66423l1.35754-1.74481a6.14642,6.14642,0,0,1,1.01616,1.95995c.0628.54677-.47954,1.163-.75338,1.74846C51.92847,91.03561,51.43971,90.44339,50.79682,89.66423Z"/><path d="M79.7083,75.52546c.48577-1.448.84059-2.5057,1.24187-3.70182C81.85567,73.925,81.65841,74.73756,79.7083,75.52546Z"/><path d="M44.12531,88.24508a9.73247,9.73247,0,0,1,1.02187-.91533,6.00615,6.00615,0,0,1,1.23774,1.3077c.06464.099-.56824.82452-.61532.79773A16.2951,16.2951,0,0,1,44.12531,88.24508Z"/><path d="M52.80279,79.59158l.46926-4.3877.68426.08313-.57913,4.42907Z"/></g><text x="0" y="115" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif">Created by Roman</text><text x="0" y="120" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif">from the Noun Project</text></svg>
@@ -0,0 +1,16 @@
1
+ import { App } from '@openedx/frontend-base';
2
+
3
+ const config: App = {
4
+ appId: 'test-example-page-app',
5
+ routes: [{
6
+ path: '/',
7
+ lazy: async () => {
8
+ const { default: Component } = await import('./ExamplePage');
9
+ return {
10
+ Component,
11
+ };
12
+ },
13
+ }]
14
+ };
15
+
16
+ export default config;
@@ -0,0 +1,3 @@
1
+ # Test i18n directories
2
+
3
+ These test files are used by the `src/i18n/scripts/intl-imports.test.js` file.
@@ -0,0 +1,4 @@
1
+ {
2
+ "learning.accessExpiration.deadline": "قم بالترقية قبل {date} للاستفادة من دخول غير محدود للمساق طالما هو موجود على الموقع.",
3
+ "learning.accessExpiration.header": "تنتهي صلاحية دخول المساق كمستمع في {date}"
4
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "learning.accessExpiration.deadline": "Mejora de categoría antes del {fecha} para obtener acceso ilimitado al curso mientras exista en el sitio.",
3
+ "learning.accessExpiration.header": "El acceso a tomar el curso de forma gratuita expira el {fecha}"
4
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "learning.accessExpiration.header3": "تنتهي صلاحية دخول المساق كمستمع في {date}"
3
+ }
@@ -0,0 +1,14 @@
1
+ import { IFrameContentWrapper } from '@openedx/frontend-base';
2
+
3
+ export default function IframeWidget() {
4
+ return (
5
+ <IFrameContentWrapper>
6
+ <section className="bg-light p-3 h-100">
7
+ <h4>Inserted iFrame Widget</h4>
8
+ <p>
9
+ This is a component that lives in the test-site but is loaded into the page via an iframe. This emulates a real-world scenario. It is NOT testing for cross-origin security issues though, since it&apos;s on the same host name.
10
+ </p>
11
+ </section>
12
+ </IFrameContentWrapper>
13
+ );
14
+ }
@@ -0,0 +1,16 @@
1
+ import { App } from '@openedx/frontend-base';
2
+
3
+ const config: App = {
4
+ appId: 'iframe-test-app',
5
+ routes: [{
6
+ path: '/iframe-plugin',
7
+ lazy: async () => {
8
+ const { default: Component } = await import('./IframeWidget');
9
+ return {
10
+ Component,
11
+ };
12
+ },
13
+ }]
14
+ };
15
+
16
+ export default config;
@@ -0,0 +1,3 @@
1
+ export { default as authenticatedPageConfig } from './authenticated-page';
2
+ export { default as examplePageConfig } from './example-page';
3
+ export { default as iframeWidgetConfig } from './iframe-widget';
@@ -0,0 +1,11 @@
1
+ import { defineMessages } from '@openedx/frontend-base';
2
+
3
+ const messages = defineMessages({
4
+ 'test-site.message': {
5
+ id: 'test-site.message',
6
+ defaultMessage: 'This message proves that i18n is working.',
7
+ description: 'A message that proves that internationalization is working.',
8
+ },
9
+ });
10
+
11
+ export default messages;
@@ -0,0 +1,11 @@
1
+ @use '@openedx/frontend-base/shell/app.scss';
2
+
3
+ $h3-color: red;
4
+
5
+ .red-text {
6
+ color: $h3-color;
7
+ }
8
+
9
+ .text-align-right {
10
+ text-align: right;
11
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "extends": "@openedx/frontend-base/config/tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": ".",
5
+ "outDir": "dist"
6
+ },
7
+ "include": [
8
+ "eslint.config.js",
9
+ "jest.config.js",
10
+ "site.config.*.tsx",
11
+ "src/**/*",
12
+ "app.d.ts",
13
+ ],
14
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * This Babel configuration file is for Jest. The Webpack build does not use Babel.
3
+ */
4
+ module.exports = {
5
+ presets: [
6
+ [
7
+ require.resolve('@babel/preset-env'), {
8
+ targets: { node: 'current' },
9
+ },
10
+ ],
11
+ [
12
+ require.resolve('@babel/preset-react'), {
13
+ runtime: 'automatic',
14
+ },
15
+ ],
16
+ require.resolve('@babel/preset-typescript'),
17
+ ],
18
+ env: {
19
+ i18n: {
20
+ plugins: [
21
+ [
22
+ 'formatjs',
23
+ ],
24
+ ],
25
+ },
26
+ },
27
+ };
@@ -0,0 +1,3 @@
1
+ const config = require('./babel/babel.config');
2
+
3
+ module.exports = config;
@@ -0,0 +1,29 @@
1
+ # i18n/scripts
2
+
3
+ This directory contains the `transifex-utils.js` and `intl-imports.js` files which are shared across all micro-frontends.
4
+
5
+ The package.json of `frontend-base` includes the following sections:
6
+
7
+ ```
8
+ "bin": {
9
+ "intl-imports.js": "i18n/scripts/intl-imports.js"
10
+ "transifex-utils.js": "i18n/scripts/transifex-utils.js"
11
+ },
12
+ ```
13
+
14
+ This config block causes boths scripts to be copied to the following path when `frontend-base` is installed as a
15
+ dependency of a micro-frontend:
16
+
17
+ ```
18
+ /node_modules/.bin/intl-imports.js
19
+ /node_modules/.bin/transifex-utils.js
20
+ ```
21
+
22
+ All micro-frontends have a `Makefile` with a line that loads the scripts from the above path:
23
+
24
+ ```
25
+ intl_imports = ./node_modules/.bin/intl-imports.js
26
+ transifex_utils = ./node_modules/.bin/transifex-utils.js
27
+ ```
28
+
29
+ So if you delete either of the files or the `scripts` directory, you'll break all micro-frontend builds. Happy coding!
@@ -0,0 +1,9 @@
1
+ import { execSync } from 'child_process';
2
+ import path from 'path';
3
+
4
+ export default function pack() {
5
+ const destination = process.argv[2];
6
+ execSync('npm run release', { stdio: 'inherit' });
7
+ const { filename } = JSON.parse(execSync('npm pack --json').toString())[0];
8
+ execSync(`npm --prefix ../${destination} install ${path.resolve(process.cwd(), filename)}`, { stdio: 'inherit' });
9
+ }
@@ -0,0 +1,27 @@
1
+ import chalk from 'chalk';
2
+ import { execSync } from 'child_process';
3
+ import { existsSync, rmSync } from 'fs';
4
+ import path from 'path';
5
+
6
+ export default function release() {
7
+ const tsconfigPath = path.resolve(process.cwd(), './tsconfig.build.json');
8
+ if (!existsSync(tsconfigPath)) {
9
+ console.error(chalk.red('openedx release: the library must include a tsconfig.build.json. Aborting.'));
10
+ process.exit(1);
11
+ }
12
+
13
+ // Clean up our dist folder.
14
+ rmSync(path.resolve(process.cwd(), 'dist'), { recursive: true, force: true });
15
+
16
+ execSync(`tsc --project ${path.resolve(process.cwd(), './tsconfig.build.json')}`, { stdio: 'inherit' });
17
+
18
+ // Copy all non JS/TS files from src into dist. This is so imports of our assets still work.
19
+ execSync(`rsync -aR src/**/* --exclude='*.tsx' --exclude='*.ts' --exclude='*.js' --exclude='*.jsx' dist/`);
20
+
21
+ // The above rsync command will put the files in dist/src - move them up a folder into dist,
22
+ // merging them into the compiled code there, and then delete dist/src.
23
+ if (existsSync(path.resolve(process.cwd(), 'dist/src'))) {
24
+ execSync('cp -R dist/src/* dist');
25
+ execSync('rm -rf dist/src');
26
+ }
27
+ }
@@ -0,0 +1,43 @@
1
+ import chalk from 'chalk';
2
+ import compression from 'compression';
3
+ import express from 'express';
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+
7
+ function isDirectoryEmpty(directoryPath: string) {
8
+ try {
9
+ const files = fs.readdirSync(directoryPath);
10
+ return files.length === 0;
11
+ } catch (error: any) {
12
+ if (error.code === 'ENOENT') {
13
+ // Directory does not exist, so treat it as empty.
14
+ return true;
15
+ }
16
+ throw error; // Throw the error for other cases
17
+ }
18
+ }
19
+
20
+ const buildPath = path.join(process.cwd(), 'dist');
21
+ const buildPathIndex = path.join(buildPath, 'index.html');
22
+
23
+ if (isDirectoryEmpty(buildPath)) {
24
+ const formattedBuildCmd = chalk.bold.redBright('``npm run build``');
25
+ console.log(chalk.bold.red(`ERROR: No build found. Please run ${formattedBuildCmd} first.`));
26
+ } else {
27
+ const app = express();
28
+
29
+ app.use(compression());
30
+ app.use(express.static(buildPath));
31
+ app.use('*', (req, res) => {
32
+ res.sendFile(buildPathIndex);
33
+ });
34
+
35
+ // Fallback to standard example port if no PORT config is set.
36
+ const PORT = process.env.PORT ?? 8080;
37
+
38
+ app.listen(PORT, () => {
39
+ const formattedServedFile = chalk.bold.cyanBright(buildPathIndex);
40
+ const formattedPort = chalk.bold.cyanBright(PORT);
41
+ console.log(chalk.greenBright(`Serving ${formattedServedFile} on port ${formattedPort}...`));
42
+ });
43
+ }