diff --git a/.changeset/afraid-lies-explain.md b/.changeset/afraid-lies-explain.md new file mode 100644 index 000000000..3f304b95f --- /dev/null +++ b/.changeset/afraid-lies-explain.md @@ -0,0 +1,7 @@ +--- +"@callstack/repack": major +--- + +BREAKING: `config.devtool` is now used to control the behaviour of generated sourcemaps. To enable sourcemaps again, please remove `devtool: false` from your config or set it explicitly to one of valid values (e.g. `source-map`). + +Introduced a dedicated `SourceMapPlugin` that consolidates sourcemap configuration and improves sourcemap handling by relying on the `devtool` option. The plugin is part of the Repack plugin and does not need to be added separately. diff --git a/apps/tester-app/rspack.config.mjs b/apps/tester-app/rspack.config.mjs index fdeefbfd9..768aef0d9 100644 --- a/apps/tester-app/rspack.config.mjs +++ b/apps/tester-app/rspack.config.mjs @@ -27,7 +27,6 @@ export default (env) => { return { mode, - devtool: false, context, entry: './index.js', resolve: { diff --git a/apps/tester-app/webpack.config.mjs b/apps/tester-app/webpack.config.mjs index 3f524f5dc..79369d689 100644 --- a/apps/tester-app/webpack.config.mjs +++ b/apps/tester-app/webpack.config.mjs @@ -27,7 +27,6 @@ export default (env) => { return { mode, - devtool: false, context, cache: process.env.USE_CACHE ? { diff --git a/apps/tester-federation-v2/configs/rspack.host-app.mjs b/apps/tester-federation-v2/configs/rspack.host-app.mjs index cf9f8490a..98e29fb8e 100644 --- a/apps/tester-federation-v2/configs/rspack.host-app.mjs +++ b/apps/tester-federation-v2/configs/rspack.host-app.mjs @@ -23,7 +23,6 @@ export default (env) => { return { mode, - devtool: false, context, entry: './src/host/index.js', resolve: { diff --git a/apps/tester-federation-v2/configs/rspack.mini-app.mjs b/apps/tester-federation-v2/configs/rspack.mini-app.mjs index ffdcf2aa1..2bedf8f9a 100644 --- a/apps/tester-federation-v2/configs/rspack.mini-app.mjs +++ b/apps/tester-federation-v2/configs/rspack.mini-app.mjs @@ -20,7 +20,6 @@ export default (env) => { return { mode, - devtool: false, context, entry: './src/mini/index.js', resolve: { diff --git a/apps/tester-federation-v2/configs/webpack.host-app.mjs b/apps/tester-federation-v2/configs/webpack.host-app.mjs index 030bd2da0..9581ec7a3 100644 --- a/apps/tester-federation-v2/configs/webpack.host-app.mjs +++ b/apps/tester-federation-v2/configs/webpack.host-app.mjs @@ -25,7 +25,6 @@ export default (env) => { return { mode, - devtool: false, context, entry: './src/host/index.js', resolve: { diff --git a/apps/tester-federation-v2/configs/webpack.mini-app.mjs b/apps/tester-federation-v2/configs/webpack.mini-app.mjs index 6fef51f68..24336e28e 100644 --- a/apps/tester-federation-v2/configs/webpack.mini-app.mjs +++ b/apps/tester-federation-v2/configs/webpack.mini-app.mjs @@ -22,7 +22,6 @@ export default (env) => { return { mode, - devtool: false, context, entry: './src/mini/index.js', resolve: { diff --git a/apps/tester-federation/configs/rspack.host-app.mjs b/apps/tester-federation/configs/rspack.host-app.mjs index be88c4301..b6a883516 100644 --- a/apps/tester-federation/configs/rspack.host-app.mjs +++ b/apps/tester-federation/configs/rspack.host-app.mjs @@ -25,7 +25,6 @@ export default (env) => { /** @type {import('@rspack/core').Configuration} */ const config = { mode, - devtool: false, context, entry: './src/host/index.js', resolve: { diff --git a/apps/tester-federation/configs/rspack.mini-app.mjs b/apps/tester-federation/configs/rspack.mini-app.mjs index 58297fda4..a8d2b9180 100644 --- a/apps/tester-federation/configs/rspack.mini-app.mjs +++ b/apps/tester-federation/configs/rspack.mini-app.mjs @@ -22,7 +22,6 @@ export default (env) => { /** @type {import('@rspack/core').Configuration} */ const config = { mode, - devtool: false, context, entry: './src/mini/index.js', resolve: { diff --git a/apps/tester-federation/configs/webpack.host-app.mjs b/apps/tester-federation/configs/webpack.host-app.mjs index 72ff6259f..4fd4994f4 100644 --- a/apps/tester-federation/configs/webpack.host-app.mjs +++ b/apps/tester-federation/configs/webpack.host-app.mjs @@ -25,7 +25,6 @@ export default (env) => { return { mode, - devtool: false, context, entry: './src/host/index.js', resolve: { diff --git a/apps/tester-federation/configs/webpack.mini-app.mjs b/apps/tester-federation/configs/webpack.mini-app.mjs index 6c4a64bed..975503728 100644 --- a/apps/tester-federation/configs/webpack.mini-app.mjs +++ b/apps/tester-federation/configs/webpack.mini-app.mjs @@ -22,7 +22,6 @@ export default (env) => { return { mode, - devtool: false, context, entry: './src/mini/index.js', resolve: { diff --git a/packages/repack/src/commands/common/config/getRepackConfig.ts b/packages/repack/src/commands/common/config/getRepackConfig.ts index 340e68117..641e19438 100644 --- a/packages/repack/src/commands/common/config/getRepackConfig.ts +++ b/packages/repack/src/commands/common/config/getRepackConfig.ts @@ -1,5 +1,6 @@ export function getRepackConfig() { return { + devtool: 'source-map', output: { publicPath: 'noop:///', }, diff --git a/packages/repack/src/plugins/DevelopmentPlugin.ts b/packages/repack/src/plugins/DevelopmentPlugin.ts index 94eda8987..bd8555d01 100644 --- a/packages/repack/src/plugins/DevelopmentPlugin.ts +++ b/packages/repack/src/plugins/DevelopmentPlugin.ts @@ -127,19 +127,6 @@ export class DevelopmentPlugin implements RspackPluginInstance { // setup HMR new compiler.webpack.HotModuleReplacementPlugin().apply(compiler); - // setup HMR source maps - new compiler.webpack.SourceMapDevToolPlugin({ - test: /\.hot-update\.js$/, - filename: '[file].map', - append: `//# sourceMappingURL=[url]?platform=${this.config.platform}`, - module: true, - columns: true, - noSources: false, - namespace: - compiler.options.output.devtoolNamespace ?? - compiler.options.output.uniqueName, - }).apply(compiler); - // setup React Refresh manually instead of using the official plugin // to avoid issues with placement of reactRefreshEntry new compiler.webpack.ProvidePlugin({ diff --git a/packages/repack/src/plugins/RepackPlugin.ts b/packages/repack/src/plugins/RepackPlugin.ts index 2e224e82e..2f6304a1a 100644 --- a/packages/repack/src/plugins/RepackPlugin.ts +++ b/packages/repack/src/plugins/RepackPlugin.ts @@ -6,6 +6,7 @@ import { LoggerPlugin, type LoggerPluginConfig } from './LoggerPlugin.js'; import { NativeEntryPlugin } from './NativeEntryPlugin.js'; import { OutputPlugin, type OutputPluginConfig } from './OutputPlugin/index.js'; import { RepackTargetPlugin } from './RepackTargetPlugin/index.js'; +import { SourceMapPlugin } from './SourceMapPlugin.js'; /** * {@link RepackPlugin} configuration options. @@ -145,20 +146,8 @@ export class RepackPlugin implements RspackPluginInstance { }).apply(compiler); if (this.config.sourceMaps) { - // TODO Fix sourcemap directory structure - // Right now its very messy and not every node module is inside of the node module - // like React Devtools backend etc or some symilinked module appear with relative path - // We should normalize this through a custom handler and provide an output similar to Metro - new compiler.webpack.SourceMapDevToolPlugin({ - test: /\.(js)?bundle$/, - filename: '[file].map', - append: `//# sourceMappingURL=[url]?platform=${this.config.platform}`, - module: true, - columns: true, - noSources: false, - namespace: - compiler.options.output.devtoolNamespace ?? - compiler.options.output.uniqueName, + new SourceMapPlugin({ + platform: this.config.platform, }).apply(compiler); } diff --git a/packages/repack/src/plugins/SourceMapPlugin.ts b/packages/repack/src/plugins/SourceMapPlugin.ts new file mode 100644 index 000000000..1421f7191 --- /dev/null +++ b/packages/repack/src/plugins/SourceMapPlugin.ts @@ -0,0 +1,69 @@ +import type { Compiler, RspackPluginInstance } from '@rspack/core'; +import { ConfigurationError } from './utils/ConfigurationError.js'; + +interface SourceMapPluginConfig { + platform?: string; +} + +export class SourceMapPlugin implements RspackPluginInstance { + constructor(private config: SourceMapPluginConfig = {}) {} + + apply(compiler: Compiler) { + // if devtool is explicitly set to false, skip generating source maps + if (!compiler.options.devtool) { + return; + } + + const format = compiler.options.devtool; + // disable builtin sourcemap generation + compiler.options.devtool = false; + + const platform = this.config.platform ?? (compiler.name as string); + + // explicitly fallback to uniqueName if devtoolNamespace is not set + const devtoolNamespace = + compiler.options.output.devtoolNamespace ?? + compiler.options.output.uniqueName; + const devtoolModuleFilenameTemplate = + compiler.options.output.devtoolModuleFilenameTemplate; + const devtoolFallbackModuleFilenameTemplate = + compiler.options.output.devtoolFallbackModuleFilenameTemplate; + + if (format.startsWith('eval')) { + throw new ConfigurationError( + '[RepackSourceMapPlugin] Eval source maps are not supported. ' + + 'Please use a different setting for `config.devtool`.' + ); + } + + if (format.startsWith('inline')) { + throw new ConfigurationError( + '[RepackSourceMapPlugin] Inline source maps are not supported. ' + + 'Please use a different setting for `config.devtool`.' + ); + } + + const hidden = format.includes('hidden'); + const cheap = format.includes('cheap'); + const moduleMaps = format.includes('module'); + const noSources = format.includes('nosources'); + + // TODO Fix sourcemap directory structure + // Right now its very messy and not every node module is inside of the node module + // like React Devtools backend etc or some symilinked module appear with relative path + // We should normalize this through a custom handler and provide an output similar to Metro + new compiler.webpack.SourceMapDevToolPlugin({ + test: /\.([cm]?jsx?|bundle)$/, + filename: '[file].map', + moduleFilenameTemplate: devtoolModuleFilenameTemplate, + fallbackModuleFilenameTemplate: devtoolFallbackModuleFilenameTemplate, + append: hidden + ? false + : `//# sourceMappingURL=[url]?platform=${platform}`, + module: moduleMaps ? true : !cheap, + columns: !cheap, + noSources, + namespace: devtoolNamespace, + }).apply(compiler); + } +} diff --git a/packages/repack/src/plugins/utils/ConfigurationError.ts b/packages/repack/src/plugins/utils/ConfigurationError.ts new file mode 100644 index 000000000..0dde41fc2 --- /dev/null +++ b/packages/repack/src/plugins/utils/ConfigurationError.ts @@ -0,0 +1,13 @@ +import { VERBOSE_ENV_KEY } from '../../env.js'; + +export class ConfigurationError extends Error { + constructor(message: string) { + super(message); + this.name = 'ConfigurationError'; + + // hide stack trace in non-verbose mode + if (!process.env[VERBOSE_ENV_KEY]) { + this.stack = undefined; + } + } +} diff --git a/templates_v5/rspack.config.cjs b/templates_v5/rspack.config.cjs index 2dc199463..63cb1cdef 100644 --- a/templates_v5/rspack.config.cjs +++ b/templates_v5/rspack.config.cjs @@ -35,11 +35,6 @@ module.exports = (env) => { return { mode, - /** - * This should be always `false`, since the Source Map configuration is done - * by `SourceMapDevToolPlugin`. - */ - devtool: false, context, entry, resolve: { diff --git a/templates_v5/rspack.config.mjs b/templates_v5/rspack.config.mjs index 9d139d560..2c93eda6e 100644 --- a/templates_v5/rspack.config.mjs +++ b/templates_v5/rspack.config.mjs @@ -39,11 +39,6 @@ export default (env) => { return { mode, - /** - * This should be always `false`, since the Source Map configuration is done - * by `SourceMapDevToolPlugin`. - */ - devtool: false, context, entry, resolve: { diff --git a/templates_v5/webpack.config.cjs b/templates_v5/webpack.config.cjs index 3c459cd51..c9c0388a5 100644 --- a/templates_v5/webpack.config.cjs +++ b/templates_v5/webpack.config.cjs @@ -46,11 +46,6 @@ module.exports = (env) => { return { mode, - /** - * This should be always `false`, since the Source Map configuration is done - * by `SourceMapDevToolPlugin`. - */ - devtool: false, context, /** * `getInitializationEntries` will return necessary entries with setup and initialization code. diff --git a/templates_v5/webpack.config.mjs b/templates_v5/webpack.config.mjs index 48a6784c2..77b335279 100644 --- a/templates_v5/webpack.config.mjs +++ b/templates_v5/webpack.config.mjs @@ -50,11 +50,6 @@ export default (env) => { return { mode, - /** - * This should be always `false`, since the Source Map configuration is done - * by `SourceMapDevToolPlugin`. - */ - devtool: false, context, entry, resolve: {