Skip to content

Commit 40aa7d8

Browse files
committed
build: refactor rollup config
1 parent e22b5c5 commit 40aa7d8

File tree

3 files changed

+179
-199
lines changed

3 files changed

+179
-199
lines changed

rollup.config.mjs

Lines changed: 152 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'
1212
import terser from '@rollup/plugin-terser'
1313
import esbuild from 'rollup-plugin-esbuild'
1414
import alias from '@rollup/plugin-alias'
15+
import { entries } from './scripts/aliases.mjs'
1516

1617
if (!process.env.TARGET) {
1718
throw new Error('TARGET package must be specified via --environment flag.')
@@ -31,9 +32,6 @@ const pkg = require(resolve(`package.json`))
3132
const packageOptions = pkg.buildOptions || {}
3233
const name = packageOptions.filename || path.basename(packageDir)
3334

34-
// ensure TS checks only once for each build
35-
let hasTSChecked = false
36-
3735
const outputConfigs = {
3836
'esm-bundler': {
3937
file: resolve(`dist/${name}.esm-bundler.js`),
@@ -104,6 +102,9 @@ function createConfig(format, output, plugins = []) {
104102
const isGlobalBuild = /global/.test(format)
105103
const isCompatPackage = pkg.name === '@vue/compat'
106104
const isCompatBuild = !!packageOptions.compat
105+
const isBrowserBuild =
106+
(isGlobalBuild || isBrowserESMBuild || isBundlerESMBuild) &&
107+
!packageOptions.enableNonBrowserBranches
107108

108109
output.exports = isCompatPackage ? 'auto' : 'named'
109110
if (isNodeBuild) {
@@ -116,42 +117,6 @@ function createConfig(format, output, plugins = []) {
116117
output.name = packageOptions.name
117118
}
118119

119-
// package aliases
120-
// TODO reuse between rollup and vitest
121-
const resolveEntryForPkg = p =>
122-
path.resolve(
123-
fileURLToPath(import.meta.url),
124-
`../packages/${p}/src/index.ts`
125-
)
126-
const dirs = readdirSync(new URL('./packages', import.meta.url))
127-
const entries = {
128-
vue: resolveEntryForPkg('vue'),
129-
'vue/compiler-sfc': resolveEntryForPkg('compiler-sfc'),
130-
'vue/server-renderer': resolveEntryForPkg('server-renderer'),
131-
'@vue/compat': resolveEntryForPkg('vue-compat')
132-
}
133-
for (const dir of dirs) {
134-
const key = `@vue/${dir}`
135-
if (dir !== 'vue' && !(key in entries)) {
136-
entries[key] = resolveEntryForPkg(dir)
137-
}
138-
}
139-
const aliasPlugin = alias({
140-
entries
141-
})
142-
143-
const tsPlugin = esbuild({
144-
tsconfig: path.resolve(__dirname, 'tsconfig.json'),
145-
sourceMap: output.sourcemap,
146-
minify: false,
147-
target: isServerRenderer || isNodeBuild ? 'es2019' : 'es2015'
148-
})
149-
150-
// we only need to check TS and generate declarations once for each build.
151-
// it also seems to run into weird issues when checking multiple times
152-
// during a single build.
153-
hasTSChecked = true
154-
155120
let entryFile = /runtime$/.test(format) ? `src/runtime.ts` : `src/index.ts`
156121

157122
// the compat build needs both default AND named exports. This will cause
@@ -163,85 +128,170 @@ function createConfig(format, output, plugins = []) {
163128
: `src/esm-index.ts`
164129
}
165130

166-
let external = []
167-
const treeShakenDeps = ['source-map', '@babel/parser', 'estree-walker']
131+
function resolveDefine() {
132+
const replacements = {
133+
__COMMIT__: `"${process.env.COMMIT}"`,
134+
__VERSION__: `"${masterVersion}"`,
135+
// this is only used during Vue's internal tests
136+
__TEST__: `false`,
137+
// If the build is expected to run directly in the browser (global / esm builds)
138+
__BROWSER__: String(isBrowserBuild),
139+
__GLOBAL__: String(isGlobalBuild),
140+
__ESM_BUNDLER__: String(isBundlerESMBuild),
141+
__ESM_BROWSER__: String(isBrowserESMBuild),
142+
// is targeting Node (SSR)?
143+
__NODE_JS__: String(isNodeBuild),
144+
// need SSR-specific branches?
145+
__SSR__: String(isNodeBuild || isBundlerESMBuild || isServerRenderer),
146+
147+
// 2.x compat build
148+
__COMPAT__: String(isCompatBuild),
149+
150+
// feature flags
151+
__FEATURE_SUSPENSE__: `true`,
152+
__FEATURE_OPTIONS_API__: isBundlerESMBuild
153+
? `__VUE_OPTIONS_API__`
154+
: `true`,
155+
__FEATURE_PROD_DEVTOOLS__: isBundlerESMBuild
156+
? `__VUE_PROD_DEVTOOLS__`
157+
: `false`
158+
}
168159

169-
if (isGlobalBuild || isBrowserESMBuild || isCompatPackage) {
170-
if (!packageOptions.enableNonBrowserBranches) {
171-
// normal browser builds - non-browser only imports are tree-shaken,
172-
// they are only listed here to suppress warnings.
173-
external = treeShakenDeps
160+
if (!isBundlerESMBuild) {
161+
// hard coded dev/prod builds
162+
// @ts-ignore
163+
replacements.__DEV__ = String(!isProductionBuild)
174164
}
175-
} else {
176-
// Node / esm-bundler builds.
177-
// externalize all direct deps unless it's the compat build.
178-
external = [
179-
...Object.keys(pkg.dependencies || {}),
180-
...Object.keys(pkg.peerDependencies || {}),
181-
// for @vue/compiler-sfc / server-renderer
182-
...['path', 'url', 'stream'],
183-
// somehow these throw warnings for runtime-* package builds
184-
...treeShakenDeps
185-
]
165+
166+
// allow inline overrides like
167+
//__RUNTIME_COMPILE__=true pnpm build runtime-core
168+
Object.keys(replacements).forEach(key => {
169+
if (key in process.env) {
170+
replacements[key] = process.env[key]
171+
}
172+
})
173+
return replacements
186174
}
187175

188-
// we are bundling forked consolidate.js in compiler-sfc which dynamically
189-
// requires a ton of template engines which should be ignored.
190-
let cjsIgnores = []
191-
if (pkg.name === '@vue/compiler-sfc') {
192-
cjsIgnores = [
193-
...Object.keys(consolidatePkg.devDependencies),
194-
'vm',
195-
'crypto',
196-
'react-dom/server',
197-
'teacup/lib/express',
198-
'arc-templates/dist/es5',
199-
'then-pug',
200-
'then-jade'
201-
]
176+
// esbuild define is a bit strict and only allows literal json or identifiers
177+
// so we still need replace plugin in some cases
178+
function resolveReplace() {
179+
const replacements = {}
180+
181+
if (isProductionBuild && isBrowserBuild) {
182+
Object.assign(replacements, {
183+
'context.onError(': `/*#__PURE__*/ context.onError(`,
184+
'emitError(': `/*#__PURE__*/ emitError(`,
185+
'createCompilerError(': `/*#__PURE__*/ createCompilerError(`,
186+
'createDOMCompilerError(': `/*#__PURE__*/ createDOMCompilerError(`
187+
})
188+
}
189+
190+
if (isBundlerESMBuild) {
191+
Object.assign(replacements, {
192+
// preserve to be handled by bundlers
193+
__DEV__: `(process.env.NODE_ENV !== 'production')`
194+
})
195+
}
196+
197+
// for compiler-sfc browser build inlined deps
198+
if (isBrowserESMBuild) {
199+
Object.assign(replacements, {
200+
'process.env': '({})',
201+
'process.platform': '""',
202+
'process.stdout': 'null'
203+
})
204+
}
205+
206+
if (Object.keys(replacements).length) {
207+
// @ts-ignore
208+
return [replace({ values: replacements, preventAssignment: true })]
209+
} else {
210+
return []
211+
}
212+
}
213+
214+
function resolveExternal() {
215+
const treeShakenDeps = ['source-map', '@babel/parser', 'estree-walker']
216+
217+
if (isGlobalBuild || isBrowserESMBuild || isCompatPackage) {
218+
if (!packageOptions.enableNonBrowserBranches) {
219+
// normal browser builds - non-browser only imports are tree-shaken,
220+
// they are only listed here to suppress warnings.
221+
return treeShakenDeps
222+
}
223+
} else {
224+
// Node / esm-bundler builds.
225+
// externalize all direct deps unless it's the compat build.
226+
return [
227+
...Object.keys(pkg.dependencies || {}),
228+
...Object.keys(pkg.peerDependencies || {}),
229+
// for @vue/compiler-sfc / server-renderer
230+
...['path', 'url', 'stream'],
231+
// somehow these throw warnings for runtime-* package builds
232+
...treeShakenDeps
233+
]
234+
}
202235
}
203236

204-
const nodePlugins =
205-
(format === 'cjs' && Object.keys(pkg.devDependencies || {}).length) ||
206-
packageOptions.enableNonBrowserBranches
207-
? [
208-
commonJS({
209-
sourceMap: false,
210-
ignore: cjsIgnores
211-
}),
212-
...(format === 'cjs' ? [] : [polyfillNode()]),
213-
nodeResolve()
214-
]
215-
: []
216-
217-
if (format === 'cjs') {
218-
nodePlugins.push(cjsReExportsPatchPlugin())
237+
function resolveNodePlugins() {
238+
// we are bundling forked consolidate.js in compiler-sfc which dynamically
239+
// requires a ton of template engines which should be ignored.
240+
let cjsIgnores = []
241+
if (pkg.name === '@vue/compiler-sfc') {
242+
cjsIgnores = [
243+
...Object.keys(consolidatePkg.devDependencies),
244+
'vm',
245+
'crypto',
246+
'react-dom/server',
247+
'teacup/lib/express',
248+
'arc-templates/dist/es5',
249+
'then-pug',
250+
'then-jade'
251+
]
252+
}
253+
254+
const nodePlugins =
255+
(format === 'cjs' && Object.keys(pkg.devDependencies || {}).length) ||
256+
packageOptions.enableNonBrowserBranches
257+
? [
258+
commonJS({
259+
sourceMap: false,
260+
ignore: cjsIgnores
261+
}),
262+
...(format === 'cjs' ? [] : [polyfillNode()]),
263+
nodeResolve()
264+
]
265+
: []
266+
267+
if (format === 'cjs') {
268+
nodePlugins.push(cjsReExportsPatchPlugin())
269+
}
270+
271+
return nodePlugins
219272
}
220273

221274
return {
222275
input: resolve(entryFile),
223276
// Global and Browser ESM builds inlines everything so that they can be
224277
// used alone.
225-
external,
278+
external: resolveExternal(),
226279
plugins: [
227280
json({
228281
namedExports: false
229282
}),
230-
aliasPlugin,
231-
tsPlugin,
232-
createReplacePlugin(
233-
isProductionBuild,
234-
isBundlerESMBuild,
235-
isBrowserESMBuild,
236-
// isBrowserBuild?
237-
(isGlobalBuild || isBrowserESMBuild || isBundlerESMBuild) &&
238-
!packageOptions.enableNonBrowserBranches,
239-
isGlobalBuild,
240-
isNodeBuild,
241-
isCompatBuild,
242-
isServerRenderer
243-
),
244-
...nodePlugins,
283+
alias({
284+
entries
285+
}),
286+
...resolveReplace(),
287+
esbuild({
288+
tsconfig: path.resolve(__dirname, 'tsconfig.json'),
289+
sourceMap: output.sourcemap,
290+
minify: false,
291+
target: isServerRenderer || isNodeBuild ? 'es2019' : 'es2015',
292+
define: resolveDefine()
293+
}),
294+
...resolveNodePlugins(),
245295
...plugins
246296
],
247297
output,
@@ -256,81 +306,6 @@ function createConfig(format, output, plugins = []) {
256306
}
257307
}
258308

259-
function createReplacePlugin(...args) {
260-
return replace({
261-
// @ts-ignore
262-
values: createReplacements(...args),
263-
preventAssignment: true
264-
})
265-
}
266-
267-
function createReplacements(
268-
isProduction,
269-
isBundlerESMBuild,
270-
isBrowserESMBuild,
271-
isBrowserBuild,
272-
isGlobalBuild,
273-
isNodeBuild,
274-
isCompatBuild,
275-
isServerRenderer
276-
) {
277-
const replacements = {
278-
__COMMIT__: `"${process.env.COMMIT}"`,
279-
__VERSION__: `"${masterVersion}"`,
280-
__DEV__: isBundlerESMBuild
281-
? // preserve to be handled by bundlers
282-
`(process.env.NODE_ENV !== 'production')`
283-
: // hard coded dev/prod builds
284-
String(!isProduction),
285-
// this is only used during Vue's internal tests
286-
__TEST__: `false`,
287-
// If the build is expected to run directly in the browser (global / esm builds)
288-
__BROWSER__: isBrowserBuild,
289-
__GLOBAL__: isGlobalBuild,
290-
__ESM_BUNDLER__: isBundlerESMBuild,
291-
__ESM_BROWSER__: isBrowserESMBuild,
292-
// is targeting Node (SSR)?
293-
__NODE_JS__: isNodeBuild,
294-
// need SSR-specific branches?
295-
__SSR__: isNodeBuild || isBundlerESMBuild || isServerRenderer,
296-
297-
// for compiler-sfc browser build inlined deps
298-
...(isBrowserESMBuild
299-
? {
300-
'process.env': '({})',
301-
'process.platform': '""',
302-
'process.stdout': 'null'
303-
}
304-
: {}),
305-
306-
// 2.x compat build
307-
__COMPAT__: isCompatBuild,
308-
309-
// feature flags
310-
__FEATURE_SUSPENSE__: `true`,
311-
__FEATURE_OPTIONS_API__: isBundlerESMBuild ? `__VUE_OPTIONS_API__` : `true`,
312-
__FEATURE_PROD_DEVTOOLS__: isBundlerESMBuild
313-
? `__VUE_PROD_DEVTOOLS__`
314-
: `false`,
315-
...(isProduction && isBrowserBuild
316-
? {
317-
'context.onError(': `/*#__PURE__*/ context.onError(`,
318-
'emitError(': `/*#__PURE__*/ emitError(`,
319-
'createCompilerError(': `/*#__PURE__*/ createCompilerError(`,
320-
'createDOMCompilerError(': `/*#__PURE__*/ createDOMCompilerError(`
321-
}
322-
: {})
323-
}
324-
// allow inline overrides like
325-
//__RUNTIME_COMPILE__=true pnpm build runtime-core
326-
Object.keys(replacements).forEach(key => {
327-
if (key in process.env) {
328-
replacements[key] = process.env[key]
329-
}
330-
})
331-
return replacements
332-
}
333-
334309
function createProductionConfig(format) {
335310
return createConfig(format, {
336311
file: resolve(`dist/${name}.${format}.prod.js`),

0 commit comments

Comments
 (0)