Skip to content

Commit b21b9a6

Browse files
committed
Cache webpack output to speed up local dev and VRTs
Also fixes line endings of webpack.config.common.js
1 parent 7543d9f commit b21b9a6

File tree

1 file changed

+180
-178
lines changed

1 file changed

+180
-178
lines changed

config/webpack.config.common.js

Lines changed: 180 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -1,178 +1,180 @@
1-
/* eslint-disable */
2-
const path = require('path');
3-
const BASE_DIRECTORY = path.resolve(__dirname, "..");
4-
const resolve = (p) => path.resolve(BASE_DIRECTORY, p);
5-
const CopyWebpackPlugin = require('copy-webpack-plugin');
6-
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
7-
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
8-
const TerserPlugin = require('terser-webpack-plugin');
9-
const webpack = require('webpack');
10-
11-
// Read in the .env file and put into `process.env`:
12-
require('dotenv').config();
13-
14-
// Loader to remove test ids (only used in production builds)
15-
const removeTestPropsLoader = {
16-
loader: "react-remove-props-loader",
17-
options: {
18-
props: ["data-testid", "data-test-id"]
19-
},
20-
};
21-
22-
module.exports = (env) => {
23-
24-
let isProd = false;
25-
let isRenderer = false;
26-
27-
if (!!env) {
28-
isProd = env['prod'] ?? false;
29-
isRenderer = env['isRenderer'] ?? false;
30-
}
31-
32-
return {
33-
stats: {
34-
errorDetails: true
35-
},
36-
37-
mode: isProd ? "production" : "development",
38-
39-
ignoreWarnings: [
40-
{ message: /node\_modules\/bootstrap\/scss\/vendor\/\_rfs\.scss/ }, // Suppress a warning which cannot be fixed without updating bootstrap
41-
{ message: /text-emphasis-variant()/ },
42-
{ message: /bg-variant()/ },
43-
],
44-
45-
devServer: {
46-
headers: {
47-
"Content-Security-Policy-Report-Only": "default-src 'self' https://cdn.isaacphysics.org https://cdn.adacomputerscience.org localhost:8080 ws://localhost:8080 https://maps.googleapis.com https://*.tile.openstreetmap.org; object-src 'none'; frame-src 'self' https://code-editor.ada-cs.org http://localhost:3000 https://anvil.works https://*.anvil.app https://www.youtube-nocookie.com; img-src 'self' localhost:8080 data: https://cdn.isaacphysics.org https://cdn.adacomputerscience.org https://i.ytimg.com https://maps.googleapis.com https://*.tile.openstreetmap.org; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://cdn.isaacphysics.org https://cdn.adacomputerscience.org https://fonts.gstatic.com;",
48-
"Feature-Policy": "geolocation 'none'; camera 'none'; microphone 'none'; accelerometer 'none';",
49-
"X-Clacks-Overhead": "GNU Terry Pratchett",
50-
},
51-
allowedHosts: "all"
52-
},
53-
54-
output: {
55-
publicPath: "/",
56-
pathinfo: !isProd,
57-
filename: isProd ? 'static/js/[name].[contenthash:8].js' : 'static/js/[name].js',
58-
chunkFilename: isProd ? 'static/js/[name].[contenthash:8].chunk.js' : 'static/js/[name].chunk.js',
59-
},
60-
61-
resolve: {
62-
modules: [path.resolve(__dirname), 'node_modules'],
63-
extensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs'],
64-
},
65-
66-
module: {
67-
rules: [
68-
{
69-
oneOf: [
70-
{
71-
test: /\.mjs$/,
72-
include: /node_modules/,
73-
type: 'javascript/auto'
74-
},
75-
{
76-
test: /\.[jt]sx?$/,
77-
exclude: /node_modules/,
78-
use: [
79-
{
80-
loader: 'babel-loader',
81-
options: {
82-
presets: ["@babel/preset-env", "@babel/preset-react"],
83-
plugins: [
84-
"@babel/plugin-transform-class-properties",
85-
"@babel/plugin-transform-classes"
86-
]
87-
}
88-
},
89-
{
90-
loader: 'ts-loader',
91-
options: {
92-
compilerOptions: {
93-
noEmit: false,
94-
jsx: "react",
95-
},
96-
},
97-
}
98-
].concat(isProd ? [removeTestPropsLoader] : []),
99-
},
100-
{
101-
test: /node_modules[\/\\](query-string|split-on-first|strict-uri-encode|d3.*)[\/\\].*\.js$/,
102-
use: [
103-
{
104-
loader: 'babel-loader',
105-
options: {
106-
presets: ["@babel/preset-env"],
107-
plugins: ["@babel/plugin-transform-modules-commonjs"]
108-
}
109-
},
110-
],
111-
},
112-
{
113-
test: /\.scss$/,
114-
use: [
115-
'style-loader',
116-
isProd ? { loader: MiniCssExtractPlugin.loader, options: { esModule: false } } : null,
117-
{
118-
loader: 'css-loader',
119-
options: {
120-
url: {
121-
filter: (url) => {
122-
// The "/assets" directory is a special case and should be ignored:
123-
return !url.startsWith("/assets");
124-
}
125-
}
126-
}
127-
},
128-
'sass-loader',
129-
].filter(Boolean),
130-
},
131-
{
132-
test: /\.(png|gif|jpg|svg)$/,
133-
type: 'asset/resource',
134-
generator: {
135-
filename: isProd ? 'static/assets/[name].[contenthash:8][ext]' : 'static/assets/[name][ext]',
136-
}
137-
},
138-
{
139-
test: /\.(ttf|woff2?|eot)$/,
140-
type: 'asset/resource',
141-
generator: {
142-
filename: isProd ? 'static/fonts/[name].[contenthash:8][ext]' : 'static/fonts/[name][ext]',
143-
}
144-
}
145-
],
146-
},
147-
],
148-
},
149-
150-
optimization: {
151-
splitChunks: {
152-
chunks: "all",
153-
},
154-
runtimeChunk: true,
155-
},
156-
157-
devtool : "source-map",
158-
159-
plugins: [
160-
isProd ? new CleanWebpackPlugin() : null, // Clear the build directory before writing output of a successful build.
161-
new MiniCssExtractPlugin({
162-
filename: isProd ? 'static/css/[name].[contenthash:8].css' : 'static/css/[name].css',
163-
chunkFilename: isProd ? 'static/css/[name].[contenthash:8].chunk.css' : 'static/css/[name].chunk.css',
164-
}),
165-
new CopyWebpackPlugin({
166-
patterns: [{
167-
from: resolve('public/assets'),
168-
to: 'assets',
169-
}
170-
]}),
171-
new webpack.DefinePlugin({
172-
REACT_APP_API_VERSION: `"${process.env.REACT_APP_API_VERSION}"`,
173-
ENV_QUIZ_FEATURE_FLAG: process.env.QUIZ_FEATURE && process.env.QUIZ_FEATURE.trim() === "true",
174-
EDITOR_PREVIEW: JSON.stringify(isRenderer)
175-
}),
176-
].filter(Boolean),
177-
};
178-
};
1+
/* eslint-disable */
2+
const path = require('path');
3+
const BASE_DIRECTORY = path.resolve(__dirname, "..");
4+
const resolve = (p) => path.resolve(BASE_DIRECTORY, p);
5+
const CopyWebpackPlugin = require('copy-webpack-plugin');
6+
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
7+
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
8+
const TerserPlugin = require('terser-webpack-plugin');
9+
const webpack = require('webpack');
10+
11+
// Read in the .env file and put into `process.env`:
12+
require('dotenv').config();
13+
14+
// Loader to remove test ids (only used in production builds)
15+
const removeTestPropsLoader = {
16+
loader: "react-remove-props-loader",
17+
options: {
18+
props: ["data-testid", "data-test-id"]
19+
},
20+
};
21+
22+
module.exports = (env) => {
23+
24+
let isProd = false;
25+
let isRenderer = false;
26+
27+
if (!!env) {
28+
isProd = env['prod'] ?? false;
29+
isRenderer = env['isRenderer'] ?? false;
30+
}
31+
32+
return {
33+
cache: isProd ? false : {type: 'filesystem'},
34+
35+
stats: {
36+
errorDetails: true
37+
},
38+
39+
mode: isProd ? "production" : "development",
40+
41+
ignoreWarnings: [
42+
{ message: /node\_modules\/bootstrap\/scss\/vendor\/\_rfs\.scss/ }, // Suppress a warning which cannot be fixed without updating bootstrap
43+
{ message: /text-emphasis-variant()/ },
44+
{ message: /bg-variant()/ },
45+
],
46+
47+
devServer: {
48+
headers: {
49+
"Content-Security-Policy-Report-Only": "default-src 'self' https://cdn.isaacphysics.org https://cdn.adacomputerscience.org localhost:8080 ws://localhost:8080 https://maps.googleapis.com https://*.tile.openstreetmap.org; object-src 'none'; frame-src 'self' https://code-editor.ada-cs.org http://localhost:3000 https://anvil.works https://*.anvil.app https://www.youtube-nocookie.com; img-src 'self' localhost:8080 data: https://cdn.isaacphysics.org https://cdn.adacomputerscience.org https://i.ytimg.com https://maps.googleapis.com https://*.tile.openstreetmap.org; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://cdn.isaacphysics.org https://cdn.adacomputerscience.org https://fonts.gstatic.com;",
50+
"Feature-Policy": "geolocation 'none'; camera 'none'; microphone 'none'; accelerometer 'none';",
51+
"X-Clacks-Overhead": "GNU Terry Pratchett",
52+
},
53+
allowedHosts: "all"
54+
},
55+
56+
output: {
57+
publicPath: "/",
58+
pathinfo: !isProd,
59+
filename: isProd ? 'static/js/[name].[contenthash:8].js' : 'static/js/[name].js',
60+
chunkFilename: isProd ? 'static/js/[name].[contenthash:8].chunk.js' : 'static/js/[name].chunk.js',
61+
},
62+
63+
resolve: {
64+
modules: [path.resolve(__dirname), 'node_modules'],
65+
extensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs'],
66+
},
67+
68+
module: {
69+
rules: [
70+
{
71+
oneOf: [
72+
{
73+
test: /\.mjs$/,
74+
include: /node_modules/,
75+
type: 'javascript/auto'
76+
},
77+
{
78+
test: /\.[jt]sx?$/,
79+
exclude: /node_modules/,
80+
use: [
81+
{
82+
loader: 'babel-loader',
83+
options: {
84+
presets: ["@babel/preset-env", "@babel/preset-react"],
85+
plugins: [
86+
"@babel/plugin-transform-class-properties",
87+
"@babel/plugin-transform-classes"
88+
]
89+
}
90+
},
91+
{
92+
loader: 'ts-loader',
93+
options: {
94+
compilerOptions: {
95+
noEmit: false,
96+
jsx: "react",
97+
},
98+
},
99+
}
100+
].concat(isProd ? [removeTestPropsLoader] : []),
101+
},
102+
{
103+
test: /node_modules[\/\\](query-string|split-on-first|strict-uri-encode|d3.*)[\/\\].*\.js$/,
104+
use: [
105+
{
106+
loader: 'babel-loader',
107+
options: {
108+
presets: ["@babel/preset-env"],
109+
plugins: ["@babel/plugin-transform-modules-commonjs"]
110+
}
111+
},
112+
],
113+
},
114+
{
115+
test: /\.scss$/,
116+
use: [
117+
'style-loader',
118+
isProd ? { loader: MiniCssExtractPlugin.loader, options: { esModule: false } } : null,
119+
{
120+
loader: 'css-loader',
121+
options: {
122+
url: {
123+
filter: (url) => {
124+
// The "/assets" directory is a special case and should be ignored:
125+
return !url.startsWith("/assets");
126+
}
127+
}
128+
}
129+
},
130+
'sass-loader',
131+
].filter(Boolean),
132+
},
133+
{
134+
test: /\.(png|gif|jpg|svg)$/,
135+
type: 'asset/resource',
136+
generator: {
137+
filename: isProd ? 'static/assets/[name].[contenthash:8][ext]' : 'static/assets/[name][ext]',
138+
}
139+
},
140+
{
141+
test: /\.(ttf|woff2?|eot)$/,
142+
type: 'asset/resource',
143+
generator: {
144+
filename: isProd ? 'static/fonts/[name].[contenthash:8][ext]' : 'static/fonts/[name][ext]',
145+
}
146+
}
147+
],
148+
},
149+
],
150+
},
151+
152+
optimization: {
153+
splitChunks: {
154+
chunks: "all",
155+
},
156+
runtimeChunk: true,
157+
},
158+
159+
devtool : "source-map",
160+
161+
plugins: [
162+
isProd ? new CleanWebpackPlugin() : null, // Clear the build directory before writing output of a successful build.
163+
new MiniCssExtractPlugin({
164+
filename: isProd ? 'static/css/[name].[contenthash:8].css' : 'static/css/[name].css',
165+
chunkFilename: isProd ? 'static/css/[name].[contenthash:8].chunk.css' : 'static/css/[name].chunk.css',
166+
}),
167+
new CopyWebpackPlugin({
168+
patterns: [{
169+
from: resolve('public/assets'),
170+
to: 'assets',
171+
}
172+
]}),
173+
new webpack.DefinePlugin({
174+
REACT_APP_API_VERSION: `"${process.env.REACT_APP_API_VERSION}"`,
175+
ENV_QUIZ_FEATURE_FLAG: process.env.QUIZ_FEATURE && process.env.QUIZ_FEATURE.trim() === "true",
176+
EDITOR_PREVIEW: JSON.stringify(isRenderer)
177+
}),
178+
].filter(Boolean),
179+
};
180+
};

0 commit comments

Comments
 (0)