Skip to content

Commit 3c24819

Browse files
committed
Properly resolve polyfills in Vite 8
1 parent fc03122 commit 3c24819

6 files changed

Lines changed: 196 additions & 3 deletions

File tree

src/globals.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {
2+
type BooleanOrBuildTarget,
3+
type BuildTarget,
4+
isEnabled,
5+
} from './utils'
6+
7+
export type GlobalName = typeof globals[number]
8+
9+
export const globals = [
10+
'buffer',
11+
'global',
12+
'process',
13+
] as const
14+
15+
export const getGlobalsToHandle = (options: {
16+
globals: { [Name in GlobalName]: BooleanOrBuildTarget },
17+
target: BuildTarget,
18+
}): GlobalName[] => {
19+
return globals.filter((global) => {
20+
const value = options.globals[global]
21+
22+
return isEnabled(value, options.target)
23+
})
24+
}

src/index.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import stdLibBrowser from 'node-stdlib-browser'
44
import { handleCircularDependancyWarning } from 'node-stdlib-browser/helpers/rollup/plugin'
55
import esbuildPlugin from 'node-stdlib-browser/helpers/esbuild/plugin'
66
import type { Plugin } from 'vite'
7+
import { getModulesToPolyfill } from './modules'
8+
import { buildTrailingSlashNormalizer } from './plugins'
79
import {
810
type BooleanOrBuildTarget,
911
type ModuleName,
@@ -136,6 +138,16 @@ export const nodePolyfills = (options: PolyfillOptions = {}): Plugin[] => {
136138
},
137139
}
138140

141+
const modulesToPolyfill = getModulesToPolyfill({
142+
modulesToExclude: optionsResolved.exclude,
143+
modulesToInclude: optionsResolved.include,
144+
})
145+
146+
const trailingSlashNormalizer = buildTrailingSlashNormalizer({
147+
modules: modulesToPolyfill,
148+
protocolImports: optionsResolved.protocolImports,
149+
})
150+
139151
const isExcluded = (moduleName: ModuleName) => {
140152
if (optionsResolved.include.length > 0) {
141153
return !optionsResolved.include.some((includedName) => compareModuleNames(moduleName, includedName))
@@ -209,9 +221,11 @@ export const nodePolyfills = (options: PolyfillOptions = {}): Plugin[] => {
209221
const plugin: Plugin = {
210222
name: 'vite-plugin-node-polyfills',
211223
config(config, env) {
224+
const isBuild = env.command === 'build'
212225
const isDev = env.command === 'serve'
213226
// @ts-expect-error - this.meta.rolldownVersion only exists with rolldown-vite 7+
214227
const isRolldownVite = !!this?.meta?.rolldownVersion
228+
const isNativeInjectAvailable = isBuild && isRolldownVite
215229

216230
// https://github.com/niksy/node-stdlib-browser/blob/3e7cd7f3d115ac5c4593b550e7d8c4a82a0d4ac4/README.md?plain=1#L203-L209
217231
const defines = {
@@ -227,7 +241,6 @@ export const nodePolyfills = (options: PolyfillOptions = {}): Plugin[] => {
227241
...(isEnabled(optionsResolved.globals.process, 'build') ? { process: 'vite-plugin-node-polyfills/shims/process' } : {}),
228242
}
229243

230-
const isNativeInjectAvailable = env.command === 'build' && isRolldownVite
231244
rawInjectPlugin = (Object.keys(shimsToInject).length > 0 && !isNativeInjectAvailable) ? inject(shimsToInject) as Plugin : false
232245
if (rawInjectPlugin === false) {
233246
delete injectPlugin.transform
@@ -272,6 +285,7 @@ export const nodePolyfills = (options: PolyfillOptions = {}): Plugin[] => {
272285
define: defines,
273286
},
274287
plugins: [
288+
trailingSlashNormalizer,
275289
{
276290
name: 'vite-plugin-node-polyfills:optimizer',
277291
banner: isDev ? globalShimsBanner : undefined,
@@ -320,8 +334,10 @@ export const nodePolyfills = (options: PolyfillOptions = {}): Plugin[] => {
320334
}
321335
},
322336
}
337+
323338
return [
339+
trailingSlashNormalizer,
324340
injectPlugin,
325341
plugin,
326-
]
342+
].flat()
327343
}

src/modules.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
export type ModuleName = typeof modules[number]
2+
export type ModuleNameWithNodePrefix = `node:${ModuleName}`
3+
4+
export const modules = [
5+
'_stream_duplex',
6+
'_stream_passthrough',
7+
'_stream_readable',
8+
'_stream_transform',
9+
'_stream_writable',
10+
'assert',
11+
'buffer',
12+
'child_process',
13+
'cluster',
14+
'console',
15+
'constants',
16+
'crypto',
17+
'dgram',
18+
'dns',
19+
'domain',
20+
'events',
21+
'fs',
22+
'http',
23+
'http2',
24+
'https',
25+
'module',
26+
'net',
27+
'os',
28+
'path',
29+
'process',
30+
'punycode',
31+
'querystring',
32+
'readline',
33+
'repl',
34+
'stream',
35+
'string_decoder',
36+
'sys',
37+
'timers',
38+
'timers/promises',
39+
'tls',
40+
'tty',
41+
'url',
42+
'util',
43+
'vm',
44+
'zlib',
45+
] as const
46+
47+
export const getModulesToPolyfill = ({
48+
modulesToExclude,
49+
modulesToInclude,
50+
}: {
51+
modulesToExclude: ModuleName[],
52+
modulesToInclude: ModuleName[],
53+
}): ModuleName[] => {
54+
return modules.filter((module) => {
55+
if (modulesToInclude.length > 0) {
56+
return modulesToInclude.includes(module)
57+
}
58+
59+
return !modulesToExclude.includes(module)
60+
})
61+
}
62+
63+
export const isModuleName = (name: string): name is ModuleName => {
64+
return modules.includes(name as ModuleName)
65+
}

src/plugins.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { type Plugin } from 'vite'
2+
import { globals } from './globals'
3+
import { type ModuleName } from './modules'
4+
import * as regex from './regex'
5+
6+
export const buildTrailingSlashNormalizer = ({
7+
modules,
8+
protocolImports,
9+
}: {
10+
modules: ModuleName[],
11+
protocolImports: boolean,
12+
}): Plugin[] => {
13+
const trailingSlashNormalizerRegex = regex.compose([
14+
regex.any([
15+
regex.join([
16+
regex.when(
17+
protocolImports,
18+
regex.optional('node:'),
19+
),
20+
regex.any(modules),
21+
]),
22+
regex.join([
23+
'vite-plugin-node-polyfills/shims/',
24+
regex.any(globals),
25+
]),
26+
]),
27+
'/',
28+
])
29+
30+
return [
31+
{
32+
// Vite v8.0.0+ does not support trailing slashes on package subpaths.
33+
name: 'vite-plugin-node-polyfills:trailing-slash-normalizer',
34+
enforce: 'pre',
35+
resolveId: {
36+
// @ts-expect-error This property is only supported in Vite v6.3.0+, so
37+
// we must run the check inside the handler to maintain compatibility
38+
// with older Vite versions.
39+
filter: { id: trailingSlashNormalizerRegex },
40+
async handler(source, importer, options) {
41+
if (!trailingSlashNormalizerRegex.test(source)) {
42+
return
43+
}
44+
45+
const sourceWithoutTrailingSlash = source.replace(/\/$/, '')
46+
47+
return this.resolve(sourceWithoutTrailingSlash, importer, {
48+
...options,
49+
skipSelf: true,
50+
})
51+
},
52+
},
53+
},
54+
]
55+
}

src/regex.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
export const any = (patterns: readonly string[]) => {
2+
return group(patterns.join('|'))
3+
}
4+
5+
export const compose = (patterns: readonly string[]) => {
6+
const pattern = patterns.join('')
7+
8+
return new RegExp(`^${pattern}$`)
9+
}
10+
11+
export const group = (pattern: string) => {
12+
return `(?:${pattern})`
13+
}
14+
15+
export const join = (patterns: readonly string[]) => {
16+
return patterns.join('')
17+
}
18+
19+
export const optional = (pattern: string) => {
20+
return `${group(pattern)}?`
21+
}
22+
23+
export const when = (condition: boolean, pattern: string, fallback = '') => {
24+
if (condition) {
25+
return pattern
26+
}
27+
28+
return fallback
29+
}

src/utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type stdLibBrowser from 'node-stdlib-browser'
1+
import stdLibBrowser from 'node-stdlib-browser'
22
import { type Plugin } from 'vite'
33

44
export type BuildTarget = 'build' | 'dev'
@@ -33,6 +33,10 @@ export const isEnabled = (value: BooleanOrBuildTarget, target: BuildTarget) => {
3333
return value === target
3434
}
3535

36+
export const isModuleName = (name: string): name is ModuleName => {
37+
return name in stdLibBrowser
38+
}
39+
3640
export const isNodeProtocolImport = (name: string) => {
3741
return name.startsWith('node:')
3842
}

0 commit comments

Comments
 (0)