Skip to content

Commit 3d182a3

Browse files
committed
webpack handlers
1 parent 03c920b commit 3d182a3

File tree

4 files changed

+117
-45
lines changed

4 files changed

+117
-45
lines changed

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
},
1919
"dependencies": {
2020
"react-scripts": "^5.0.1",
21-
"typescript": ">=5",
22-
"webpack": "^5.90.0"
21+
"typescript": ">=5"
2322
},
2423
"devDependencies": {
24+
"@types/fs-extra": "^11.0.4",
2525
"@types/node": ">=16",
2626
"@types/webpack": "^5.28.5"
2727
}
28-
}
28+
}

src/index.ts

+96-36
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import path from "path";
22
import webpack, { Configuration } from "webpack";
3+
import fs from "fs-extra";
34

45
type PluginName = "react";
56
const PLUGIN_NAME: PluginName = "react";
@@ -154,35 +155,51 @@ class ServerlessReact {
154155
this.hooks = {
155156
initialize: async () => {},
156157
"react:validate": async () => {
157-
console.log("!!!! react:validate");
158+
this.log.verbose("react:validate");
158159
},
159160
"react:build": async () => {
160-
console.log("!!!! react:build");
161+
this.log.verbose("react:build");
161162
},
162163
"before:offline:start": async () => {
163-
this.log.verbose("before:offline:start");
164-
await this.build();
164+
const { config, compiler } = await this.build();
165+
await this.watch(config, compiler);
165166
},
166167
"before:offline:start:init": async () => {
167-
this.log.verbose("before:offline:start:init");
168-
await this.build();
168+
const { config, compiler } = await this.build();
169+
await this.watch(config, compiler);
169170
},
170171
};
171172
}
172173

173-
build = async (): Promise<void> => {
174+
build = async (): Promise<{
175+
config: webpack.Configuration;
176+
compiler: webpack.Compiler;
177+
}> => {
174178
// TODO Check if react-scripts exists
179+
process.env.BABEL_ENV = "production";
180+
process.env.NODE_ENV = "production";
175181

176-
const webpackConfig = path.join(
182+
require(path.join(
183+
this.serverlessConfig.servicePath,
184+
this.pluginConfig.webpackConfig || "node_modules/react-scripts/config/env"
185+
));
186+
187+
const paths = require(path.join(
188+
this.serverlessConfig.servicePath,
189+
this.pluginConfig.webpackConfig ||
190+
"node_modules/react-scripts/config/paths"
191+
));
192+
193+
const { checkBrowsers } = require("react-dev-utils/browsersHelper");
194+
await checkBrowsers(paths.appPath, false);
195+
196+
const configFactory = require(path.join(
177197
this.serverlessConfig.servicePath,
178198
this.pluginConfig.webpackConfig ||
179199
"node_modules/react-scripts/config/webpack.config.js"
180-
);
200+
));
181201

182-
const configFactory = require(webpackConfig);
183-
const config: Configuration = configFactory(
184-
process.env.NODE_ENV === "development" ? "development" : "production"
185-
);
202+
const config: Configuration = configFactory("production");
186203

187204
if (!config.output) {
188205
throw new Error("No output config in webpack config");
@@ -193,40 +210,83 @@ class ServerlessReact {
193210
`.${PLUGIN_NAME}`
194211
);
195212

196-
// TODO use config.entry as a fallback
197-
// config.entry = path.join(
198-
// this.serverlessConfig.servicePath,
199-
// this.pluginConfig.entryPoint || "src/index.js"
200-
// );
201-
202-
// TODO appSrc
203-
// TODO publicUrlOrPath
204-
205-
// TODO Copy public dir
213+
fs.emptyDirSync(config.output.path);
214+
fs.copySync(paths.appPublic, config.output.path, {
215+
dereference: true,
216+
filter: (file) => file !== paths.appHtml,
217+
});
206218

207219
const compiler = webpack(config);
208220

209221
return new Promise((resolve, reject) => {
222+
this.log.verbose(`[${config.entry}] Starting webpack build...`);
223+
210224
compiler.run((err, stats) => {
211-
if (err) {
212-
return reject(err);
213-
}
214-
if (!stats) {
215-
return reject(new Error("No stats from webpack"));
216-
}
217-
if (stats.hasErrors()) {
218-
// TODO Formatting like build.js
219-
return reject(new Error(stats.toJson().errors?.join("\n\n")));
225+
try {
226+
this.handleWebpackError(config, err);
227+
} catch (error: any) {
228+
this.log.error(`[${config.entry}] ${error.message}`);
229+
return reject();
220230
}
221231

222-
// TODO fail on process.env.CI + warnings
223-
console.log("Compiled with warnings.\n");
224-
console.log(stats.toJson().warnings?.join("\n\n"));
232+
try {
233+
this.handleWebpackStats(config, stats);
234+
} catch (error: any) {
235+
this.log.error(`[${config.entry}] ${error.message}`);
236+
return reject();
237+
}
225238

226-
resolve();
239+
this.log.verbose(`[${config.entry}] Webpack build complete.`);
240+
resolve({ config, compiler });
227241
});
228242
});
229243
};
244+
245+
watch = async (
246+
config: webpack.Configuration,
247+
_compiler: webpack.Compiler
248+
) => {
249+
this.log.verbose(`[${config.entry}] TODO: Watching for changes...`);
250+
};
251+
252+
handleWebpackError = (
253+
_config: webpack.Configuration,
254+
error: Error | null | undefined
255+
) => {
256+
if (!error) {
257+
return;
258+
}
259+
260+
throw new Error(error.message);
261+
};
262+
263+
handleWebpackStats = (
264+
_config: webpack.Configuration,
265+
stats?: webpack.Stats
266+
) => {
267+
if (!stats) {
268+
throw new Error(`Webpack did not emit stats.`);
269+
}
270+
271+
const statsJson = stats.toJson();
272+
273+
const { errors, warnings } = statsJson;
274+
275+
if (errors && errors.length > 0) {
276+
throw new Error(`Webpack failed to compile:\n${errors.join("\n\n")}`);
277+
}
278+
279+
if (warnings && warnings.length > 0) {
280+
const message = `Webpack compiled with warnings:\n${warnings.join(
281+
"\n\n"
282+
)}`;
283+
if (process.env.CI) {
284+
throw new Error(message);
285+
} else {
286+
this.log.warning(message);
287+
}
288+
}
289+
};
230290
}
231291

232292
module.exports = ServerlessReact;

tsconfig.json

+2-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
/* Basic Options */
55
"incremental": true,
66
"target": "ESNext",
7-
"module": "Node16",
7+
"module": "CommonJS",
88
"rootDir": "./src",
99
"outDir": "./",
1010
"sourceMap": false,
@@ -13,7 +13,6 @@
1313

1414
/* Strict Type-Checking Options */
1515
"strict": true,
16-
"noImplicitAny": true,
1716
"strictNullChecks": true,
1817
"strictFunctionTypes": true,
1918
"strictBindCallApply": true,
@@ -28,10 +27,8 @@
2827
"noFallthroughCasesInSwitch": true,
2928

3029
/* Module Resolution Options */
31-
"moduleResolution": "Node16",
3230
"baseUrl": "./",
3331
"esModuleInterop": true,
34-
"resolveJsonModule": true,
3532

3633
/* Experimental Options */
3734
"experimentalDecorators": true,
@@ -40,5 +37,5 @@
4037
/* Advanced Options */
4138
"forceConsistentCasingInFileNames": true
4239
},
43-
"exclude": ["node_modules/**/*"]
40+
"exclude": ["node_modules/**/*", "examples/**/*"]
4441
}

yarn.lock

+16-1
Original file line numberDiff line numberDiff line change
@@ -1939,6 +1939,14 @@
19391939
"@types/qs" "*"
19401940
"@types/serve-static" "*"
19411941

1942+
"@types/fs-extra@^11.0.4":
1943+
version "11.0.4"
1944+
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-11.0.4.tgz#e16a863bb8843fba8c5004362b5a73e17becca45"
1945+
integrity sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==
1946+
dependencies:
1947+
"@types/jsonfile" "*"
1948+
"@types/node" "*"
1949+
19421950
"@types/graceful-fs@^4.1.2":
19431951
version "4.1.9"
19441952
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4"
@@ -1992,6 +2000,13 @@
19922000
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
19932001
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
19942002

2003+
"@types/jsonfile@*":
2004+
version "6.1.4"
2005+
resolved "https://registry.yarnpkg.com/@types/jsonfile/-/jsonfile-6.1.4.tgz#614afec1a1164e7d670b4a7ad64df3e7beb7b702"
2006+
integrity sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==
2007+
dependencies:
2008+
"@types/node" "*"
2009+
19952010
"@types/mime@*":
19962011
version "3.0.4"
19972012
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-3.0.4.tgz#2198ac274de6017b44d941e00261d5bc6a0e0a45"
@@ -9046,7 +9061,7 @@ webpack-sources@^3.2.3:
90469061
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
90479062
integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
90489063

9049-
webpack@^5, webpack@^5.64.4, webpack@^5.90.0:
9064+
webpack@^5, webpack@^5.64.4:
90509065
version "5.90.0"
90519066
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.90.0.tgz#313bfe16080d8b2fee6e29b6c986c0714ad4290e"
90529067
integrity sha512-bdmyXRCXeeNIePv6R6tGPyy20aUobw4Zy8r0LUS2EWO+U+Ke/gYDgsCh7bl5rB6jPpr4r0SZa6dPxBxLooDT3w==

0 commit comments

Comments
 (0)