-
Notifications
You must be signed in to change notification settings - Fork 39
feat: expose PARAGON as a global variable
#365
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
49b201a
af90f45
82c5614
bbbf690
73ba105
0c34718
5f7d76f
2a78f67
d987b08
cda3812
0e0dfcc
86bc18a
74a0a4f
4daff04
4d94653
1d17036
f9b47e7
bd710ac
39cc967
782b91c
5a7af2e
84c6d76
091b34d
84cbeec
6f6f1ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| const path = require('path'); | ||
| const fs = require('fs'); | ||
|
|
||
| /** | ||
| * Attempts to extract the Paragon version from the `node_modules` of | ||
| * the consuming application. | ||
| * | ||
| * @param {string} dir Path to directory containing `node_modules`. | ||
| * @returns {string} Paragon dependency version of the consuming application | ||
| */ | ||
| function getParagonVersion(dir) { | ||
| const pathToPackageJson = `${dir}/node_modules/@edx/paragon/package.json`; | ||
| if (!fs.existsSync(pathToPackageJson)) { | ||
| return undefined; | ||
| } | ||
| return JSON.parse(fs.readFileSync(pathToPackageJson)).version; | ||
| } | ||
|
|
||
| /** | ||
| * @typedef {Object} ParagonThemeCssAsset | ||
| * @property {string} filePath | ||
| * @property {string} entryName | ||
| * @property {string} outputChunkName | ||
| */ | ||
|
|
||
| /** | ||
| * @typedef {Object} ParagonThemeVariantCssAsset | ||
| * @property {string} filePath | ||
| * @property {string} entryName | ||
| * @property {string} outputChunkName | ||
| * @property {boolean} default | ||
| * @property {boolean} dark | ||
| */ | ||
|
|
||
| /** | ||
| * @typedef {Object} ParagonThemeCss | ||
| * @property {ParagonThemeCssAsset} core The metadata about the core Paragon theme CSS | ||
| * @property {Object.<string, ParagonThemeVariantCssAsset>} variants A collection of theme variants. | ||
| */ | ||
|
|
||
| /** | ||
| * Attempts to extract the Paragon theme CSS from the locally installed `@edx/paragon` package. | ||
| * @param {string} dir Path to directory containing `node_modules`. | ||
| * @returns {ParagonThemeCss} | ||
| */ | ||
| function getParagonThemeCss(dir) { | ||
| const pathToParagonThemeOutput = path.resolve(dir, './node_modules/@edx/paragon', 'dist', 'paragon-theme.json'); | ||
| if (!fs.existsSync(pathToParagonThemeOutput)) { | ||
| return undefined; | ||
| } | ||
| const paragonConfig = JSON.parse(fs.readFileSync(pathToParagonThemeOutput)); | ||
| const { | ||
| core: themeCore, | ||
| variants: themeVariants, | ||
| } = paragonConfig?.themeUrls || {}; | ||
|
|
||
| const pathToCoreCss = path.resolve(dir, './node_modules/@edx/paragon', 'dist', themeCore.paths.minified); | ||
| const coreCssExists = fs.existsSync(pathToCoreCss); | ||
|
|
||
| const validThemeVariantPaths = Object.entries(themeVariants || {}).filter(([, value]) => { | ||
| const themeVariantCssDefault = path.resolve(dir, './node_modules/@edx/paragon', 'dist', value.paths.default); | ||
| const themeVariantCssMinified = path.resolve(dir, './node_modules/@edx/paragon', 'dist', value.paths.minified); | ||
| return fs.existsSync(themeVariantCssDefault) && fs.existsSync(themeVariantCssMinified); | ||
| }); | ||
|
|
||
| if (!coreCssExists || validThemeVariantPaths.length === 0) { | ||
| return undefined; | ||
| } | ||
| const coreResult = { | ||
| filePath: path.resolve(dir, pathToCoreCss), | ||
| entryName: 'paragon.theme.core', | ||
| outputChunkName: 'paragon-theme-core', | ||
| }; | ||
|
|
||
| const themeVariantResults = {}; | ||
| validThemeVariantPaths.forEach(([themeVariant, value]) => { | ||
| themeVariantResults[themeVariant] = { | ||
| filePath: path.resolve(dir, './node_modules/@edx/paragon', 'dist', value.paths.minified), | ||
| entryName: `paragon.theme.variants.${themeVariant}`, | ||
| outputChunkName: `paragon-theme-variant-${themeVariant}`, | ||
| default: value.default, | ||
| dark: value.dark, | ||
| }; | ||
| }); | ||
|
|
||
| return { | ||
| core: fs.existsSync(pathToCoreCss) ? coreResult : undefined, | ||
| variants: themeVariantResults, | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
| * Replaces all periods in a string with hyphens. | ||
| * @param {string} str A string containing periods to replace with hyphens. | ||
| * @returns The input string with periods replaced with hyphens. | ||
| */ | ||
| function replacePeriodsWithHyphens(str) { | ||
| return str.replaceAll('.', '-'); | ||
| } | ||
|
|
||
| /** | ||
| * @typedef CacheGroup | ||
| * @property {string} type The type of cache group. | ||
| * @property {string|function} name The name of the cache group. | ||
| * @property {function} chunks A function that returns true if the chunk should be included in the cache group. | ||
| * @property {boolean} enforce If true, this cache group will be created even if it conflicts with default cache groups. | ||
| */ | ||
|
|
||
| /** | ||
| * @param {ParagonThemeCss} paragonThemeCss The Paragon theme CSS metadata. | ||
| * @returns {Object.<string, CacheGroup>} The cache groups for the Paragon theme CSS. | ||
| */ | ||
| function getParagonCacheGroups(paragonThemeCss) { | ||
| const cacheGroups = {}; | ||
| if (!paragonThemeCss) { | ||
| return cacheGroups; | ||
| } | ||
| cacheGroups[paragonThemeCss.core.entryName] = { | ||
| type: 'css/mini-extract', | ||
| name: replacePeriodsWithHyphens(paragonThemeCss.core.entryName), | ||
| chunks: chunk => chunk.name === paragonThemeCss.core.entryName, | ||
| enforce: true, | ||
| }; | ||
| Object.values(paragonThemeCss.variants).forEach(({ entryName }) => { | ||
| cacheGroups[entryName] = { | ||
| type: 'css/mini-extract', | ||
| name: replacePeriodsWithHyphens(entryName), | ||
| chunks: chunk => chunk.name === entryName, | ||
| enforce: true, | ||
| }; | ||
| }); | ||
| return cacheGroups; | ||
| } | ||
|
|
||
| /** | ||
| * @param {ParagonThemeCss} paragonThemeCss The Paragon theme CSS metadata. | ||
| * @returns {Object.<string, string>} The entry points for the Paragon theme CSS. | ||
| */ | ||
| function getParagonEntryPoints(paragonThemeCss) { | ||
| const entryPoints = {}; | ||
| if (!paragonThemeCss) { | ||
| return entryPoints; | ||
| } | ||
| entryPoints[paragonThemeCss.core.entryName] = path.resolve(process.cwd(), paragonThemeCss.core.filePath); | ||
| Object.values(paragonThemeCss.variants).forEach(({ filePath, entryName }) => { | ||
| entryPoints[entryName] = path.resolve(process.cwd(), filePath); | ||
| }); | ||
| return entryPoints; | ||
| } | ||
|
|
||
| module.exports = { | ||
| getParagonVersion, | ||
| getParagonThemeCss, | ||
| getParagonCacheGroups, | ||
| getParagonEntryPoints, | ||
| replacePeriodsWithHyphens, | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,19 @@ | ||
| const path = require('path'); | ||
| const RemoveEmptyScriptsPlugin = require('webpack-remove-empty-scripts'); | ||
|
|
||
| const ParagonWebpackPlugin = require('../lib/plugins/paragon-webpack-plugin/ParagonWebpackPlugin'); | ||
| const { | ||
| getParagonThemeCss, | ||
| getParagonCacheGroups, | ||
| getParagonEntryPoints, | ||
| } = require('./data/paragonUtils'); | ||
|
|
||
| const paragonThemeCss = getParagonThemeCss(process.cwd()); | ||
|
|
||
| module.exports = { | ||
| entry: { | ||
| app: path.resolve(process.cwd(), './src/index'), | ||
| ...getParagonEntryPoints(paragonThemeCss), | ||
| }, | ||
| output: { | ||
| path: path.resolve(process.cwd(), './dist'), | ||
|
|
@@ -19,4 +30,16 @@ module.exports = { | |
| }, | ||
| extensions: ['.js', '.jsx'], | ||
| }, | ||
| optimization: { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see the various
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Put another way, it may be worth a comment in the config here describing what we're doing to the optimization and how this differs from the default (I think you're leaving the chunking the same and just adding this caching thing, but that's only cause I've stared at a lot of these in my day 😉)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct, the chunking is staying the same as is it today, with the addition of splitting out the "locally" installed already-compiled CSS files from That said, we probably should find some ways to optimize our MFE Webpack bundles (e.g., test hypothesis that many small JS files for the |
||
| splitChunks: { | ||
| chunks: 'all', | ||
| cacheGroups: { | ||
| ...getParagonCacheGroups(paragonThemeCss), | ||
| }, | ||
| }, | ||
| }, | ||
| plugins: [ | ||
| new RemoveEmptyScriptsPlugin(), | ||
| new ParagonWebpackPlugin(), | ||
| ], | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| BASE_URL='http://localhost:8080' | ||
| FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico | ||
| TEST_VARIABLE='foo' |
Uh oh!
There was an error while loading. Please reload this page.