Skip to content
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

Bw/alpha to master #431

Merged
merged 74 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
cd1e726
fix(deps): update dependency cssnano to v6 (#344)
renovate[bot] Apr 25, 2023
4b5d84a
fix(deps): update dependency html-webpack-plugin to v5.5.1
renovate[bot] Apr 25, 2023
200a8ac
fix(deps): update dependency postcss to v8.4.23
renovate[bot] Apr 25, 2023
177d154
fix(deps): update dependency webpack-cli to v5.0.2
renovate[bot] Apr 25, 2023
2af8b42
fix(deps): update dependency webpack-dev-server to v4.13.3
renovate[bot] Apr 25, 2023
0edf13f
fix(deps): update dependency sass to v1.62.1
renovate[bot] Apr 26, 2023
9908041
fix: disable dot rule in historyApiFallback in webpack.dev.config.js …
adamstankiewicz May 2, 2023
602b7a0
fix(deps): update eslint (#351)
renovate[bot] May 4, 2023
357334c
fix(deps): update dependency clean-webpack-plugin to v4 (#341)
renovate[bot] May 4, 2023
1c81573
fix(deps): update dependency @svgr/webpack to v7 (#340)
renovate[bot] May 4, 2023
e298637
fix(deps): update babel monorepo
renovate[bot] May 4, 2023
68457f1
fix(deps): update dependency cssnano to v6.0.1
renovate[bot] May 4, 2023
0519c40
fix(deps): update dependency webpack to v5.82.0 (#355)
renovate[bot] May 5, 2023
5500920
fix(deps): update dependency dotenv-webpack to v8 (#357)
renovate[bot] May 5, 2023
632a667
fix(deps): update dependency postcss-loader to v7 (#358)
renovate[bot] May 5, 2023
4a5d559
chore(deps): update dependency typescript to v5 (#338)
renovate[bot] May 5, 2023
5e4f2c2
chore(deps): update peter-evans/enable-pull-request-automerge action …
renovate[bot] May 5, 2023
1dcd666
fix(deps): update dependency @edx/new-relic-source-map-webpack-plugin…
renovate[bot] May 5, 2023
30887b1
fix(deps): update dependency postcss-rtlcss to v4 (#359)
renovate[bot] May 5, 2023
70b01a5
fix(deps): update dependency @svgr/webpack to v8 (#364)
renovate[bot] May 26, 2023
fa974a3
fix(deps): update dependency webpack-cli to v5.1.1 (#363)
renovate[bot] May 26, 2023
0e20e2b
fix(deps): update dependency postcss-loader to v7.3.1 (#367)
renovate[bot] May 26, 2023
d7d790c
fix(deps): update dependency webpack-dev-server to v4.15.0 (#362)
renovate[bot] May 26, 2023
e05d46b
fix(deps): update dependency eslint to v8.41.0 (#361)
renovate[bot] May 26, 2023
23954c4
fix(deps): update dependency style-loader to v3.3.3 (#368)
renovate[bot] May 26, 2023
a105af8
fix(deps): update dependency sass-loader to v13 (#360)
renovate[bot] May 26, 2023
1980b75
fix(deps): update dependency webpack-merge to v5.9.0 (#371)
renovate[bot] May 26, 2023
8df0d32
fix(deps): update dependency webpack to v5.84.1 (#370)
renovate[bot] May 26, 2023
6931415
fix(deps): update dependency @edx/new-relic-source-map-webpack-plugin…
renovate[bot] May 26, 2023
37313b2
fix(deps): update dependency postcss-loader to v7.3.2
renovate[bot] May 28, 2023
d3a4c0f
fix(deps): update dependency postcss to v8.4.24
renovate[bot] May 28, 2023
93a04eb
fix(deps): update dependency sass-loader to v13.3.1
renovate[bot] May 28, 2023
3a6db3f
fix(deps): update dependency webpack-cli to v5.1.2
renovate[bot] Jun 4, 2023
b6169a8
fix(deps): update dependency webpack-cli to v5.1.3
renovate[bot] Jun 4, 2023
b759a41
fix(deps): update dependency webpack-cli to v5.1.4
renovate[bot] Jun 7, 2023
10c56c1
fix(deps): update dependency webpack to v5.86.0 (#376)
renovate[bot] Jun 8, 2023
d52a18a
fix(deps): update dependency sass to v1.63.2 (#382)
renovate[bot] Jun 8, 2023
54c1f51
fix(deps): update dependency webpack-bundle-analyzer to v4.9.0 (#377)
renovate[bot] Jun 9, 2023
5e4658d
fix(deps): update babel monorepo to v7.22.5 (#372)
renovate[bot] Jun 9, 2023
466e4a0
fix(deps): update eslint (#378)
renovate[bot] Jun 9, 2023
8e0f7e4
fix(deps): update dependency html-webpack-plugin to v5.5.2
renovate[bot] Jun 9, 2023
97d45e7
fix(deps): update dependency sass to v1.63.3
renovate[bot] Jun 9, 2023
f37b842
fix(deps): update dependency webpack-dev-server to v4.15.1
renovate[bot] Jun 9, 2023
d10c1c6
fix(deps): update dependency sass-loader to v13.3.2
renovate[bot] Jun 10, 2023
8a88f62
fix(deps): update dependency postcss-loader to v7.3.3
renovate[bot] Jun 10, 2023
733ea4f
fix(deps): update dependency html-webpack-plugin to v5.5.3
renovate[bot] Jun 10, 2023
4241f47
fix(deps): update dependency postcss-custom-media to v9.1.4
renovate[bot] Jun 13, 2023
0cb6885
chore(deps): update react monorepo
renovate[bot] Jun 13, 2023
6ca555f
fix(deps): update dependency sharp to v0.32.1
renovate[bot] Jun 13, 2023
488686d
fix(deps): update dependency sass to v1.63.4
renovate[bot] Jun 14, 2023
8674978
chore(deps): update actions/setup-node action to v3 (#396)
renovate[bot] Jun 22, 2023
05edd10
chore(deps): update actions/checkout action to v3 (#395)
renovate[bot] Jun 22, 2023
c07fa91
fix(deps): update dependency image-minimizer-webpack-plugin to v3.8.3
renovate[bot] Jun 22, 2023
5b86133
fix(deps): update dependency postcss-custom-media to v9.1.5
renovate[bot] Jun 22, 2023
69899aa
fix(deps): update dependency sass to v1.63.6
renovate[bot] Jun 22, 2023
06eee29
fix(deps): update eslint (#402)
renovate[bot] Jul 6, 2023
ee71d3e
fix(deps): update dependency postcss to v8.4.25
renovate[bot] Jul 6, 2023
71ee361
fix(deps): update dependency babel-loader to v9.1.3
renovate[bot] Jul 7, 2023
cc50692
fix: updated jest to resolve word-wrap ReDoS vulnerability (#411)
BilalQamar95 Jul 11, 2023
3299605
fix(deps): update dependency sharp to v0.32.2
renovate[bot] Jul 11, 2023
64fe89f
fix: bump semver from 5.7.1 to 5.7.2 (#414)
dependabot[bot] Jul 12, 2023
85b3c54
fix(deps): update dependency @babel/eslint-parser to v7.22.9
renovate[bot] Jul 12, 2023
909fd27
fix(deps): update dependency postcss to v8.4.26
renovate[bot] Jul 13, 2023
b28e6bc
fix(deps): update dependency sharp to v0.32.3
renovate[bot] Jul 14, 2023
a5c307b
fix(deps): update dependency webpack to v5.88.1 (#403)
renovate[bot] Jul 17, 2023
cd408cd
fix(deps): update dependency webpack to v5.88.2
renovate[bot] Jul 18, 2023
088793c
feat: add fedx-scripts serve (#404)
adamstankiewicz Jul 18, 2023
a49ad49
fix(deps): update dependency postcss-custom-media to v9.1.5
renovate[bot] Jul 18, 2023
012c4ee
fix(deps): update dependency sharp to v0.32.3
renovate[bot] Jul 18, 2023
bbf58fe
fix: ensure .env.development PORT works (#423)
adamstankiewicz Jul 18, 2023
2529a1e
fix: silence sass compiler warnings (#425)
adamstankiewicz Jul 19, 2023
589b78e
fix: reverted jest upgrade (#427)
BilalQamar95 Jul 25, 2023
ca26dca
fix: update webpack common config to fix errors (#428)
solababs Aug 2, 2023
6245a84
feat: Re-enable typescript for production builds
marlonkeating Apr 14, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/sync-master-alpha.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ jobs:
name: Syncing branches
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v1
uses: actions/setup-node@v3
with:
node-version: 18
- name: Create Pull Request
Expand All @@ -29,7 +29,7 @@ jobs:
pull-request-number: ${{ steps.cpr.outputs.PULL_REQUEST_NUMBER }}
github-token: ${{ secrets.requirements_bot_github_token }}
- name: Enable Pull Request Automerge
uses: peter-evans/enable-pull-request-automerge@v2
uses: peter-evans/enable-pull-request-automerge@v3
with:
pull-request-number: ${{ steps.cpr.outputs.PULL_REQUEST_NUMBER }}
token: ${{ secrets.requirements_bot_github_token }}
35 changes: 33 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Usage
-----

CLI commands are structured: ``fedx-scripts <targetScript> <options>``. Options
are passed on to the target script, so refer to each target script's cli
are passed on to the target script, so refer to each target script's CLI
documentation to learn what options are available. Example package.json::

{
Expand All @@ -31,7 +31,8 @@ documentation to learn what options are available. Example package.json::
"precommit": "npm run lint",
"snapshot": "fedx-scripts jest --updateSnapshot",
"start": "fedx-scripts webpack-dev-server --progress",
"test": "fedx-scripts jest --coverage --passWithNoTests"
"test": "fedx-scripts jest --coverage --passWithNoTests",
"serve": "fedx-scripts serve"
},
"dependencies": {
...
Expand Down Expand Up @@ -177,6 +178,36 @@ Local module configuration for TypeScript
}
```

Serving a production Webpack build locally
------------------------------------------

In some scenarios, you may want to run a production Webpack build locally. To serve a production build locally:

#. Create an ``env.config.js`` file containing the configuration for local development, with the exception of ``NODE_ENV='production'``.
#. Run ``npm run build`` to build the production assets. The output assets will rely on the local development configuration specified in the prior step.
#. Add an NPM script ``serve`` to your application's ``package.json`` (i.e., ``"serve": "fedx-scripts serve"``).
#. Run ``npm run serve`` to serve your production build assets. It will attempt to run the build on the same port specified in the ``env.config.js`` file.

Local module configuration for TypeScript
-----------------------------------------

#. Create file in repository `tsconfig.json`, with a clause `"extends": "@edx/frontend-build"`
#. Set "rootDir" to the root of the source code folders
#. Set "include" to wildcard patterns specifying the subdirectories/files under rootDir where source code can be found
#. Include any wildcards under rootDir that should be excluded using "exclude"

```Sample json
{
"extends": "@edx/frontend-build",
"compilerOptions": {
"rootDir": ".",
"outDir": "dist"
},
"include": ["src/**/*"],
"exclude": ["dist", "node_modules"]
}
```

Development
-----------

Expand Down
8 changes: 7 additions & 1 deletion bin/fedx-scripts.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#!/usr/bin/env node

const chalk = require('chalk');

const presets = require('../lib/presets');

/**
Expand Down Expand Up @@ -65,6 +68,9 @@ switch (commandName) {
ensureConfigOption(presets.webpackDevServer);
require('webpack-dev-server/bin/webpack-dev-server');
break;
case 'serve':
require('../lib/scripts/serve');
break;
default:
console.warn(`fedx-scripts: The command ${commandName} is unsupported`);
console.log(chalk.red(`[ERROR] fedx-scripts: The command ${chalk.bold.red(commandName)} is unsupported.`));
}
18 changes: 18 additions & 0 deletions config/webpack.common.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,22 @@ module.exports = {
},
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
ignoreWarnings: [
// Ignore warnings raised by source-map-loader.
// some third party packages may ship miss-configured sourcemaps, that interrupts the build
// See: https://github.com/facebook/create-react-app/discussions/11278#discussioncomment-1780169
/**
*
* @param {import('webpack').WebpackError} warning
* @returns {boolean}
*/
function ignoreSourcemapsloaderWarnings(warning) {
return (
warning.module
&& warning.module.resource.includes('node_modules')
&& warning.details
&& warning.details.includes('source-map-loader')
);
},
],
};
3 changes: 3 additions & 0 deletions config/webpack.dev-stage.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ module.exports = merge(commonConfig, {
path.join(process.cwd(), 'node_modules'),
path.join(process.cwd(), 'src'),
],
// silences compiler warnings regarding deprecation warnings
quietDeps: true,
},
},
},
Expand Down Expand Up @@ -173,6 +175,7 @@ module.exports = merge(commonConfig, {
https: true,
historyApiFallback: {
index: path.join(PUBLIC_PATH, 'index.html'),
disableDotRule: true,
},
// Enable hot reloading server. It will provide WDS_SOCKET_PATH endpoint
// for the WebpackDevServer client so it can learn when the files were
Expand Down
3 changes: 3 additions & 0 deletions config/webpack.dev.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ module.exports = merge(commonConfig, {
path.join(process.cwd(), 'node_modules'),
path.join(process.cwd(), 'src'),
],
// silences compiler warnings regarding deprecation warnings
quietDeps: true,
},
},
},
Expand Down Expand Up @@ -175,6 +177,7 @@ module.exports = merge(commonConfig, {
port: process.env.PORT || 8080,
historyApiFallback: {
index: path.join(PUBLIC_PATH, 'index.html'),
disableDotRule: true,
},
// Enable hot reloading server. It will provide WDS_SOCKET_PATH endpoint
// for the WebpackDevServer client so it can learn when the files were
Expand Down
3 changes: 2 additions & 1 deletion config/webpack.prod.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// optimized bundles at the expense of a longer build time.

const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { merge } = require('webpack-merge');
Expand Down Expand Up @@ -132,6 +131,8 @@ module.exports = merge(commonConfig, {
path.join(process.cwd(), 'node_modules'),
path.join(process.cwd(), 'src'),
],
// silences compiler warnings regarding deprecation warnings
quietDeps: true,
},
},
},
Expand Down
37 changes: 37 additions & 0 deletions docs/0003-fedx-scripts-serve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Serving production Webpack builds locally with `fedx-scripts`

## Summary

The build-and-deploy process for micro-frontends (MFEs) throughout Open edX include running the MFE through a production Webpack build process, relying on configuration specified in a `webpack.prod.config.js` file. The resulting file assets are what ultimately get released to production and served to users. However, it is currently non-obvious how to preview the production file assets generated by `npm run build` locally should the need arise (e.g., to have more confidence in the resulting Webpack output and/or behavior before relying on the build-and-deploy process to release to a staging/production environment).

## Context

Most micro-frontends (MFEs) throughout the Open edX platform rely on a `npm run build` script that runs a production Webpack build based on the configuration specified in a `webpack.prod.config.js` file. The `webpack-prod.config.js` may be provided either by consumers in the root of their MFE's repository (i.e., typically using `createConfig` to extend/override parts of the default production Webpack configuration), or simply rely on the default `webpack.prod.config.js` configuration file provided by `@edx/frontend-build`.

The output from `npm run build` is generated in a Git-ignored `dist` directory, and contains the actual files that should be deployed to production.

Included in the `dist` directory's files is the MFE's `index.html` file that needs to be served for all routes the user may try loading. By simply loading `index.html` in the browser, it will inevitably run into some issues (e.g., not supporting React routing, etc.).

To mitigate this, this ADR describes a new mechanism to provide a standard, documented way to serve the generated assets from the production Webpack build when running `npm run build`.

# Decision

We will create a new `serve` command for `fedx-scripts` that creates an Express.js server to run the generated `dist` file assets (e.g., `index.html`) on the `PORT` specified in the MFE's `env.config.js` and/or `.env.development|private` file(s) on `localhost`.

If no `env.config.js` and/or `.env.development|private` file(s) exist and/or no `PORT` setting is specified those files, the `serve` command will fallback to a default port 8080, which is similar to the default ports our typical example MFE applications use.

# Implementation

The new `serve` command will live as under a new `scripts` directory under `lib`.

Once in place, a MFE application may add a `serve` script to its NPM scripts in the `package.json` file:

```json
{
"scripts": {
"serve": "fedx-scripts serve"
}
}
```

Then, running `npm run serve` in the root of that MFE application will run the new `serve` command in `@edx/frontend-build`, serving the assets in the MFE's `dist` directory on the `PORT` specified in the `env.config.js` file or `.env.development|private` file(s).
Empty file added example/.env
Empty file.
1 change: 1 addition & 0 deletions example/.env.development
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
PORT=3000
FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico
TEST_VARIABLE='foo'
3 changes: 2 additions & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"build": "../bin/fedx-scripts.js webpack",
"lint": "../bin/fedx-scripts.js eslint . --ext .jsx,.js",
"babel": "../bin/fedx-scripts.js babel src --out-dir dist/babel --source-maps --ignore **/*.test.jsx,**/*.test.js --copy-files",
"start": "../bin/fedx-scripts.js webpack-dev-server"
"start": "../bin/fedx-scripts.js webpack-dev-server",
"serve": "../bin/fedx-scripts.js serve"
},
"keywords": [],
"author": "",
Expand Down
78 changes: 78 additions & 0 deletions lib/scripts/serve.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
const express = require('express');
const path = require('path');
const fs = require('fs');
const chalk = require('chalk');
const dotenv = require('dotenv');

const resolvePrivateEnvConfig = require('../resolvePrivateEnvConfig');

// Add process env vars. Currently used only for setting the
// server port and the publicPath
dotenv.config({
path: path.resolve(process.cwd(), '.env.development'),
});

// Allow private/local overrides of env vars from .env.development for config settings
// that you'd like to persist locally during development, without the risk of checking
// in temporary modifications to .env.development.
resolvePrivateEnvConfig('.env.private');

function isDirectoryEmpty(directoryPath) {
try {
const files = fs.readdirSync(directoryPath);
return files.length === 0;
} catch (error) {
if (error.code === 'ENOENT') {
// Directory does not exist, so treat it as empty.
return true;
}
throw error; // Throw the error for other cases
}
}

const buildPath = path.join(process.cwd(), 'dist');
const buildPathIndex = path.join(buildPath, 'index.html');

const fallbackPort = 8080;

if (isDirectoryEmpty(buildPath)) {
const formattedBuildCmd = chalk.bold.redBright('``npm run build``');
console.log(chalk.bold.red(`ERROR: No build found. Please run ${formattedBuildCmd} first.`));
} else {
let configuredPort;

try {
configuredPort = require(path.join(process.cwd(), 'env.config.js'))?.PORT;
} catch (error) {
// Pass. Consuming applications may not have an `env.config.js` file. This is OK.
}

if (!configuredPort) {
configuredPort = process.env.PORT;
}

// No `PORT` found in `env.config.js` and/or `.env.development|private`, so output a warning.
if (!configuredPort) {
const formattedEnvDev = chalk.bold.yellowBright('.env.development');
const formattedEnvConfig = chalk.bold.yellowBright('env.config.js');
const formattedPort = chalk.bold.yellowBright(fallbackPort);
console.log(chalk.yellow(`No port found in ${formattedEnvDev} and/or ${formattedEnvConfig} file(s). Falling back to port ${formattedPort}.\n`));
}

const app = express();

// Fallback to standard example port if no PORT config is set.
const PORT = configuredPort || fallbackPort;

app.use(express.static(buildPath));

app.use('*', (req, res) => {
res.sendFile(buildPathIndex);
});

app.listen(PORT, () => {
const formattedServedFile = chalk.bold.cyanBright(buildPathIndex);
const formattedPort = chalk.bold.cyanBright(PORT);
console.log(chalk.greenBright(`Serving ${formattedServedFile} on port ${formattedPort}...`));
});
}
Loading