11// @ts -check
22
33/**
4- * Rollup config docs: https://rollupjs.org/guide/en/#big-list-of -options
4+ * Rolldown config docs: https://rolldown.rs/reference/config -options
55 */
66
77import * as fs from 'fs' ;
8- import { builtinModules , isBuiltin } from 'module' ;
8+ import { isBuiltin } from 'module' ;
99import * as path from 'path' ;
1010import { fileURLToPath } from 'url' ;
1111
1212import deepMerge from 'deepmerge' ;
1313
14- import { defineConfig } from 'rollup ' ;
14+ import { defineConfig } from 'rolldown ' ;
1515import {
1616 makeDebugBuildStatementReplacePlugin ,
17- makeEsbuildPlugin ,
1817 makeEsmCjsReplacePlugin ,
19- makeNodeResolvePlugin ,
2018 makeProductionReplacePlugin ,
2119 makeRrwebBuildPlugin ,
2220} from './plugins/index.mjs' ;
2321import { makePackageNodeEsm } from './plugins/make-esm-plugin.mjs' ;
24- import { mergeExternals , mergePlugins } from './utils.mjs' ;
22+ import { getNodeBuiltIns , mergeExternals , mergePlugins } from './utils.mjs' ;
2523
2624const __dirname = path . dirname ( fileURLToPath ( import . meta. url ) ) ;
2725
@@ -97,20 +95,17 @@ export function makeBaseNPMConfig(options = {}) {
9795 entrypoints = [ 'src/index.ts' ] ,
9896 hasBundles = false ,
9997 packageSpecificConfig = { } ,
100- esbuild = { } ,
10198 bundledBuiltins = [ ] ,
10299 } = options ;
103100
104- const nodeResolvePlugin = makeNodeResolvePlugin ( ) ;
105- const transpilePlugin = makeEsbuildPlugin ( esbuild ) ;
106101 const debugBuildStatementReplacePlugin = makeDebugBuildStatementReplacePlugin ( ) ;
107102 const rrwebBuildPlugin = makeRrwebBuildPlugin ( {
108103 excludeShadowDom : undefined ,
109104 excludeIframe : undefined ,
110105 } ) ;
111106
112107 const deps = [
113- ...builtinModules . filter ( m => ! bundledBuiltins . includes ( m ) ) ,
108+ ...getNodeBuiltIns ( bundledBuiltins ) ,
114109 ...Object . keys ( packageDotJSON . dependencies || { } ) ,
115110 ...Object . keys ( packageDotJSON . peerDependencies || { } ) ,
116111 ...Object . keys ( packageDotJSON . optionalDependencies || { } ) ,
@@ -119,6 +114,31 @@ export function makeBaseNPMConfig(options = {}) {
119114 const defaultBaseConfig = {
120115 input : entrypoints ,
121116
117+ // Point at the package's tsconfig so rolldown picks up its TypeScript & JSX settings.
118+ tsconfig : path . resolve ( process . cwd ( ) , './tsconfig.json' ) ,
119+
120+ // NOTE: we deliberately leave `platform` unset so rolldown infers it from the output format
121+ // ('node' for cjs, 'browser' for everything else). Every explicit value breaks something:
122+ // 'node' injects `import "node:module"` into each runtime chunk, which webpack rejects for
123+ // browser targets; 'neutral' rewrites `import.meta` to `{}`, so `createRequire(import.meta.url)`
124+ // gets `undefined`. Node-only packages that need the node platform for both halves set it
125+ // themselves (see server-utils and bundler-plugins).
126+
127+ // ES2020 is our floor: keeps `?.`/`??` native and downlevels everything newer. Packages that
128+ // need more (e.g. top-level await) raise it through `packageSpecificConfig`.
129+ transform : {
130+ target : 'es2020' ,
131+
132+ // The inferred 'browser' platform defines `process.env.NODE_ENV`, which folds every
133+ // `process.env.NODE_ENV !== 'development'` guard to a constant and lets DCE delete the
134+ // branch behind it. That silently dropped the orchestrion and source-map plugins from the
135+ // vite integrations' ESM output while the CJS half kept them. Mapping it to itself keeps
136+ // the runtime lookup, so the guard is evaluated by the consumer as it always was.
137+ define : {
138+ 'process.env.NODE_ENV' : 'process.env.NODE_ENV' ,
139+ } ,
140+ } ,
141+
122142 output : {
123143 // an appropriately-named directory will be added to this base value when we specify either a cjs or esm build
124144 dir : hasBundles ? 'build/npm' : 'build' ,
@@ -130,6 +150,7 @@ export function makeBaseNPMConfig(options = {}) {
130150
131151 // output individual files rather than one big bundle
132152 preserveModules : true ,
153+ preserveModulesRoot : 'src' ,
133154
134155 // Don't hoist imports into entrypoints
135156 // should be ignored when `preserveModules` is used,
@@ -139,8 +160,6 @@ export function makeBaseNPMConfig(options = {}) {
139160 // Allow wrappers or helper functions generated by rollup to use any ES2015 features
140161 generatedCode : {
141162 preset : 'es2015' ,
142- // With arrow functions, Node can't see `export *` exports when ESM code imports our CJS files.
143- arrowFunctions : false ,
144163 } ,
145164
146165 // don't add `"use strict"` to the top of cjs files
@@ -154,19 +173,17 @@ export function makeBaseNPMConfig(options = {}) {
154173 // get: () => are.great,
155174 // });
156175 externalLiveBindings : false ,
157-
158- // Don't call `Object.freeze` on the results of `import * as someModule from '...'`
159- // (We don't need it, so why waste the bytes?)
160- freeze : false ,
161-
162- // Assume externals are ESM-shaped (`__esModule` + `.default`), which our own `@sentry/*`
163- // packages satisfy via `esModule: 'if-default-prop'`. This keeps `import * as x` a live
164- // reference to the real module rather than an `_interopNamespace` copy — instrumentation code
165- // relies on that to monkey-patch modules like `fs` in place. Packages that pull in bare-CJS
166- // third-party deps (no `.default`) override this per-module (see server-utils).
167- interop : 'esModule' ,
168176 } ,
169177
178+ // NOTE: rolldown has no equivalent of rollup's `output.interop`. In the CJS build it wraps
179+ // namespace imports of externals as `x = __toESM(require('x'))`, and `__toESM` returns a copy
180+ // whose properties are getter-only forwarders. Reads pass through to the real module but writes
181+ // do not, so code that monkey-patches a module in place has to default-import it (`import x
182+ // from 'x'`, whose `.default` is the live `require()` result) rather than namespace-import it.
183+ // Rolldown errors on a statically visible `ns.foo = ...` (ASSIGN_TO_IMPORT), but it cannot see a
184+ // write made through a helper, and that one fails silently. See
185+ // `packages/node/src/integrations/fs/vendored/instrumentation.ts`.
186+
170187 treeshake : {
171188 moduleSideEffects : ( id , external ) => {
172189 if ( external === false && ignoreSideEffects . test ( id ) ) {
@@ -186,7 +203,7 @@ export function makeBaseNPMConfig(options = {}) {
186203 } ,
187204 } ,
188205
189- plugins : [ nodeResolvePlugin , transpilePlugin , debugBuildStatementReplacePlugin , rrwebBuildPlugin ] ,
206+ plugins : [ debugBuildStatementReplacePlugin , rrwebBuildPlugin ] ,
190207
191208 // don't include imported modules from outside the package in the final output
192209 // also treat subpath exports (e.g. `@sentry/core/browser`) as external
@@ -248,8 +265,7 @@ export function makeNPMConfigVariants(baseConfig, options = {}) {
248265 }
249266
250267 return variantSpecificConfigs . map ( variant =>
251- // Plugin arrays must be merged in the right order or the build silently misbehaves
252- // (e.g. esbuild strips dev-mode marker comments before the replace plugin can act).
268+ // Plugin arrays must be merged in the right order or the build silently misbehaves.
253269 deepMerge ( baseConfig , variant , {
254270 customMerge : key => ( key === 'plugins' ? mergePlugins : undefined ) ,
255271 } ) ,
0 commit comments