Fix webpack source maps (#15663)

This commit is contained in:
Steve Repsher 2023-03-16 09:38:55 -04:00 committed by GitHub
parent db62e9f922
commit aeb7f8ff36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 97 additions and 22 deletions

View File

@ -2,6 +2,15 @@ const path = require("path");
const env = require("./env.js"); const env = require("./env.js");
const paths = require("./paths.js"); const paths = require("./paths.js");
// GitHub base URL to use for production source maps
// Nightly builds use the commit SHA, otherwise assumes there is a tag that matches the version
module.exports.sourceMapURL = () => {
const ref = env.version().endsWith("dev")
? process.env.GITHUB_SHA || "dev"
: env.version();
return `https://raw.githubusercontent.com/home-assistant/frontend/${ref}`;
};
// Files from NPM Packages that should not be imported // Files from NPM Packages that should not be imported
// eslint-disable-next-line unused-imports/no-unused-vars // eslint-disable-next-line unused-imports/no-unused-vars
module.exports.ignorePackages = ({ latestBuild }) => [ module.exports.ignorePackages = ({ latestBuild }) => [
@ -65,13 +74,14 @@ const htmlMinifierOptions = {
}, },
}; };
module.exports.terserOptions = (latestBuild) => ({ module.exports.terserOptions = ({ latestBuild, isTestBuild }) => ({
safari10: !latestBuild, safari10: !latestBuild,
ecma: latestBuild ? undefined : 5, ecma: latestBuild ? undefined : 5,
output: { comments: false }, format: { comments: false },
sourceMap: !isTestBuild,
}); });
module.exports.babelOptions = ({ latestBuild, isProdBuild }) => ({ module.exports.babelOptions = ({ latestBuild, isProdBuild, isTestBuild }) => ({
babelrc: false, babelrc: false,
compact: false, compact: false,
presets: [ presets: [
@ -135,8 +145,11 @@ module.exports.babelOptions = ({ latestBuild, isProdBuild }) => ({
/node_modules[\\/]core-js/, /node_modules[\\/]core-js/,
/node_modules[\\/]webpack[\\/]buildin/, /node_modules[\\/]webpack[\\/]buildin/,
], ],
sourceMaps: !isTestBuild,
}); });
const nameSuffix = (latestBuild) => (latestBuild ? "-latest" : "-es5");
const outputPath = (outputRoot, latestBuild) => const outputPath = (outputRoot, latestBuild) =>
path.resolve(outputRoot, latestBuild ? "frontend_latest" : "frontend_es5"); path.resolve(outputRoot, latestBuild ? "frontend_latest" : "frontend_es5");
@ -159,14 +172,17 @@ BundleConfig {
latestBuild: boolean, latestBuild: boolean,
// If we're doing a stats build (create nice chunk names) // If we're doing a stats build (create nice chunk names)
isStatsBuild: boolean, isStatsBuild: boolean,
// If it's just a test build in CI, skip time on source map generation
isTestBuild: boolean,
// Names of entrypoints that should not be hashed // Names of entrypoints that should not be hashed
dontHash: Set<string> dontHash: Set<string>
} }
*/ */
module.exports.config = { module.exports.config = {
app({ isProdBuild, latestBuild, isStatsBuild, isWDS }) { app({ isProdBuild, latestBuild, isStatsBuild, isTestBuild, isWDS }) {
return { return {
name: "app" + nameSuffix(latestBuild),
entry: { entry: {
service_worker: "./src/entrypoints/service_worker.ts", service_worker: "./src/entrypoints/service_worker.ts",
app: "./src/entrypoints/app.ts", app: "./src/entrypoints/app.ts",
@ -180,12 +196,14 @@ module.exports.config = {
isProdBuild, isProdBuild,
latestBuild, latestBuild,
isStatsBuild, isStatsBuild,
isTestBuild,
isWDS, isWDS,
}; };
}, },
demo({ isProdBuild, latestBuild, isStatsBuild }) { demo({ isProdBuild, latestBuild, isStatsBuild }) {
return { return {
name: "demo" + nameSuffix(latestBuild),
entry: { entry: {
main: path.resolve(paths.demo_dir, "src/entrypoint.ts"), main: path.resolve(paths.demo_dir, "src/entrypoint.ts"),
}, },
@ -215,6 +233,7 @@ module.exports.config = {
} }
return { return {
name: "cast" + nameSuffix(latestBuild),
entry, entry,
outputPath: outputPath(paths.cast_output_root, latestBuild), outputPath: outputPath(paths.cast_output_root, latestBuild),
publicPath: publicPath(latestBuild), publicPath: publicPath(latestBuild),
@ -226,8 +245,9 @@ module.exports.config = {
}; };
}, },
hassio({ isProdBuild, latestBuild }) { hassio({ isProdBuild, latestBuild, isStatsBuild, isTestBuild }) {
return { return {
name: "supervisor" + nameSuffix(latestBuild),
entry: { entry: {
entrypoint: path.resolve(paths.hassio_dir, "src/entrypoint.ts"), entrypoint: path.resolve(paths.hassio_dir, "src/entrypoint.ts"),
}, },
@ -235,6 +255,8 @@ module.exports.config = {
publicPath: publicPath(latestBuild, paths.hassio_publicPath), publicPath: publicPath(latestBuild, paths.hassio_publicPath),
isProdBuild, isProdBuild,
latestBuild, latestBuild,
isStatsBuild,
isTestBuild,
isHassioBuild: true, isHassioBuild: true,
defineOverlay: { defineOverlay: {
__SUPERVISOR__: true, __SUPERVISOR__: true,
@ -244,6 +266,7 @@ module.exports.config = {
gallery({ isProdBuild, latestBuild }) { gallery({ isProdBuild, latestBuild }) {
return { return {
name: "gallery" + nameSuffix(latestBuild),
entry: { entry: {
entrypoint: path.resolve(paths.gallery_dir, "src/entrypoint.js"), entrypoint: path.resolve(paths.gallery_dir, "src/entrypoint.js"),
}, },

View File

@ -17,7 +17,7 @@ module.exports = {
isStatsBuild() { isStatsBuild() {
return process.env.STATS === "1"; return process.env.STATS === "1";
}, },
isTest() { isTestBuild() {
return process.env.IS_TEST === "true"; return process.env.IS_TEST === "true";
}, },
isNetlify() { isNetlify() {

View File

@ -1,8 +1,7 @@
// Run HA develop mode // Run HA develop mode
const gulp = require("gulp"); const gulp = require("gulp");
const env = require("../env"); const env = require("../env");
require("./clean.js"); require("./clean.js");
require("./translations.js"); require("./translations.js");
require("./locale-data.js"); require("./locale-data.js");
@ -50,7 +49,7 @@ gulp.task(
"copy-static-app", "copy-static-app",
env.useRollup() ? "rollup-prod-app" : "webpack-prod-app", env.useRollup() ? "rollup-prod-app" : "webpack-prod-app",
// Don't compress running tests // Don't compress running tests
...(env.isTest() ? [] : ["compress-app"]), ...(env.isTestBuild() ? [] : ["compress-app"]),
gulp.parallel( gulp.parallel(
"gen-pages-prod", "gen-pages-prod",
"gen-index-app-prod", "gen-index-app-prod",

View File

@ -1,7 +1,5 @@
const gulp = require("gulp"); const gulp = require("gulp");
const env = require("../env"); const env = require("../env");
require("./clean.js"); require("./clean.js");
require("./gen-icons-json.js"); require("./gen-icons-json.js");
require("./webpack.js"); require("./webpack.js");
@ -43,6 +41,6 @@ gulp.task(
env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio", env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio",
"gen-index-hassio-prod", "gen-index-hassio-prod",
...// Don't compress running tests ...// Don't compress running tests
(env.isTest() ? [] : ["compress-hassio"]) (env.isTestBuild() ? [] : ["compress-hassio"])
) )
); );

View File

@ -5,6 +5,7 @@ const webpack = require("webpack");
const WebpackDevServer = require("webpack-dev-server"); const WebpackDevServer = require("webpack-dev-server");
const log = require("fancy-log"); const log = require("fancy-log");
const path = require("path"); const path = require("path");
const env = require("../env");
const paths = require("../paths"); const paths = require("../paths");
const { const {
createAppConfig, createAppConfig,
@ -104,6 +105,8 @@ gulp.task("webpack-prod-app", () =>
prodBuild( prodBuild(
bothBuilds(createAppConfig, { bothBuilds(createAppConfig, {
isProdBuild: true, isProdBuild: true,
isStatsBuild: env.isStatsBuild(),
isTestBuild: env.isTestBuild(),
}) })
) )
); );
@ -161,6 +164,8 @@ gulp.task("webpack-prod-hassio", () =>
prodBuild( prodBuild(
bothBuilds(createHassioConfig, { bothBuilds(createHassioConfig, {
isProdBuild: true, isProdBuild: true,
isStatsBuild: env.isStatsBuild(),
isTestBuild: env.isTestBuild(),
}) })
) )
); );

View File

@ -76,7 +76,7 @@ const createRollupConfig = ({
}), }),
!isWDS && worker(), !isWDS && worker(),
!isWDS && dontHashPlugin({ dontHash }), !isWDS && dontHashPlugin({ dontHash }),
!isWDS && isProdBuild && terser(bundle.terserOptions(latestBuild)), !isWDS && isProdBuild && terser(bundle.terserOptions({ latestBuild })),
!isWDS && !isWDS &&
isStatsBuild && isStatsBuild &&
visualizer({ visualizer({

View File

@ -22,6 +22,7 @@ class LogStartCompilePlugin {
} }
const createWebpackConfig = ({ const createWebpackConfig = ({
name,
entry, entry,
outputPath, outputPath,
publicPath, publicPath,
@ -29,6 +30,7 @@ const createWebpackConfig = ({
isProdBuild, isProdBuild,
latestBuild, latestBuild,
isStatsBuild, isStatsBuild,
isTestBuild,
isHassioBuild, isHassioBuild,
dontHash, dontHash,
}) => { }) => {
@ -37,10 +39,16 @@ const createWebpackConfig = ({
} }
const ignorePackages = bundle.ignorePackages({ latestBuild }); const ignorePackages = bundle.ignorePackages({ latestBuild });
return { return {
name,
mode: isProdBuild ? "production" : "development", mode: isProdBuild ? "production" : "development",
target: ["web", latestBuild ? "es2017" : "es5"], target: ["web", latestBuild ? "es2017" : "es5"],
devtool: isProdBuild // For tests/CI, source maps are skipped to gain build speed
? "cheap-module-source-map" // For production, generate source maps for accurate stack traces without source code
// For development, generate "cheap" versions that can map to original line numbers
devtool: isTestBuild
? false
: isProdBuild
? "nosources-source-map"
: "eval-cheap-module-source-map", : "eval-cheap-module-source-map",
entry, entry,
node: false, node: false,
@ -51,7 +59,7 @@ const createWebpackConfig = ({
use: { use: {
loader: "babel-loader", loader: "babel-loader",
options: { options: {
...bundle.babelOptions({ latestBuild, isProdBuild }), ...bundle.babelOptions({ latestBuild, isProdBuild, isTestBuild }),
cacheDirectory: !isProdBuild, cacheDirectory: !isProdBuild,
cacheCompression: false, cacheCompression: false,
}, },
@ -68,7 +76,7 @@ const createWebpackConfig = ({
new TerserPlugin({ new TerserPlugin({
parallel: true, parallel: true,
extractComments: true, extractComments: true,
terserOptions: bundle.terserOptions(latestBuild), terserOptions: bundle.terserOptions({ latestBuild, isTestBuild }),
}), }),
], ],
moduleIds: isProdBuild && !isStatsBuild ? "deterministic" : "named", moduleIds: isProdBuild && !isStatsBuild ? "deterministic" : "named",
@ -153,6 +161,22 @@ const createWebpackConfig = ({
publicPath, publicPath,
// To silence warning in worker plugin // To silence warning in worker plugin
globalObject: "self", globalObject: "self",
// Since production source maps don't include sources, we need to point to them elsewhere
// For dependencies, just provide the path (no source in browser)
// Otherwise, point to the raw code on GitHub for browser to load
devtoolModuleFilenameTemplate:
!isTestBuild && isProdBuild
? (info) => {
const sourcePath = info.resourcePath.replace(/^\.\//, "");
if (
sourcePath.startsWith("node_modules") ||
sourcePath.startsWith("webpack")
) {
return `no-source/${sourcePath}`;
}
return `${bundle.sourceMapURL()}/${sourcePath}`;
}
: undefined,
}, },
experiments: { experiments: {
topLevelAwait: true, topLevelAwait: true,
@ -160,9 +184,14 @@ const createWebpackConfig = ({
}; };
}; };
const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => const createAppConfig = ({
isProdBuild,
latestBuild,
isStatsBuild,
isTestBuild,
}) =>
createWebpackConfig( createWebpackConfig(
bundle.config.app({ isProdBuild, latestBuild, isStatsBuild }) bundle.config.app({ isProdBuild, latestBuild, isStatsBuild, isTestBuild })
); );
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) =>
@ -173,8 +202,20 @@ const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) =>
const createCastConfig = ({ isProdBuild, latestBuild }) => const createCastConfig = ({ isProdBuild, latestBuild }) =>
createWebpackConfig(bundle.config.cast({ isProdBuild, latestBuild })); createWebpackConfig(bundle.config.cast({ isProdBuild, latestBuild }));
const createHassioConfig = ({ isProdBuild, latestBuild }) => const createHassioConfig = ({
createWebpackConfig(bundle.config.hassio({ isProdBuild, latestBuild })); isProdBuild,
latestBuild,
isStatsBuild,
isTestBuild,
}) =>
createWebpackConfig(
bundle.config.hassio({
isProdBuild,
latestBuild,
isStatsBuild,
isTestBuild,
})
);
const createGalleryConfig = ({ isProdBuild, latestBuild }) => const createGalleryConfig = ({ isProdBuild, latestBuild }) =>
createWebpackConfig(bundle.config.gallery({ isProdBuild, latestBuild })); createWebpackConfig(bundle.config.gallery({ isProdBuild, latestBuild }));

View File

@ -1,5 +1,12 @@
/* eslint-disable import/extensions */
/* eslint-disable @typescript-eslint/no-var-requires */
const { createAppConfig } = require("./build-scripts/webpack.js"); const { createAppConfig } = require("./build-scripts/webpack.js");
const { isProdBuild, isStatsBuild } = require("./build-scripts/env.js"); const {
isProdBuild,
isStatsBuild,
isTestBuild,
} = require("./build-scripts/env.js");
// This file exists because we haven't migrated the stats script yet // This file exists because we haven't migrated the stats script yet
@ -7,6 +14,7 @@ const configs = [
createAppConfig({ createAppConfig({
isProdBuild: isProdBuild(), isProdBuild: isProdBuild(),
isStatsBuild: isStatsBuild(), isStatsBuild: isStatsBuild(),
isTestBuild: isTestBuild(),
latestBuild: true, latestBuild: true,
}), }),
]; ];
@ -16,6 +24,7 @@ if (isProdBuild && !isStatsBuild) {
createAppConfig({ createAppConfig({
isProdBuild: isProdBuild(), isProdBuild: isProdBuild(),
isStatsBuild: isStatsBuild(), isStatsBuild: isStatsBuild(),
isTestBuild: isTestBuild(),
latestBuild: false, latestBuild: false,
}) })
); );