Skip to content

Commit

Permalink
fix(terser): nth_identifier: allow pure functions
Browse files Browse the repository at this point in the history
  • Loading branch information
wmertens committed Sep 7, 2024
1 parent 1a76300 commit 0d44fc5
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
"source-map-support": "^0.5.21",
"strip-ansi": "^7.1.0",
"strip-literal": "^2.1.0",
"terser": "^5.31.6",
"tsconfck": "^3.1.3",
"tslib": "^2.7.0",
"types": "link:./types",
Expand Down
45 changes: 45 additions & 0 deletions packages/vite/src/node/__tests__/plugins/terser.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import { describe, expect, test } from 'vitest'
import { build } from 'vite'
import type { RollupOutput } from 'rollup'

const __dirname = resolve(fileURLToPath(import.meta.url), '..')

describe('terser', () => {
test('nth', async () => {
const result = (await build({
root: resolve(__dirname, '../packages/build-project'),
logLevel: 'silent',
build: {
write: false,
minify: 'terser',
terserOptions: {
mangle: {
nth_identifier: {
get: (n) => {
return 'prefix_' + n.toString()
},
},
},
},
},
plugins: [
{
name: 'test',
resolveId(id) {
if (id === 'entry.js') {
return '\0' + id
}
},
load(id) {
if (id === '\0entry.js') {
return `const foo = 1;console.log(foo)`
}
},
},
],
})) as RollupOutput
expect(result.output[0].code).toContain('prefix_')
})
})
40 changes: 40 additions & 0 deletions packages/vite/src/node/plugins/terser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ const loadTerserPath = (root: string) => {
return terserPath
}

const toString = (obj: Record<string, any>, name: string) => {
if (name in obj && typeof obj[name] === 'function') {
obj[name] = obj[name].toString()
}
}

export function terserPlugin(config: ResolvedConfig): Plugin {
const { maxWorkers, ...terserOptions } = config.build.terserOptions

Expand All @@ -47,6 +53,27 @@ export function terserPlugin(config: ResolvedConfig): Plugin {
// test fails when using `import`. maybe related: https://github.com/nodejs/node/issues/43205
// eslint-disable-next-line no-restricted-globals -- this function runs inside cjs
const terser = require(terserPath)
const nth:
| Terser.SimpleIdentifierMangler
| Terser.WeightedIdentifierMangler
| undefined = (options.mangle as any)?.nth_identifier
if (nth && typeof nth === 'object') {
const toFunction = (obj: Record<string, any>, name: string) => {
if (name in obj && typeof obj[name] === 'string') {
const fn = eval(obj[name])
if (typeof fn !== 'function') {
throw new Error(
`Failed to eval nth_identifier.${name}: not a function`,
)
}
obj[name] = fn
}
}
toFunction(nth, 'get')
toFunction(nth, 'consider')
toFunction(nth, 'sort')
}

return terser.minify(code, options) as Terser.MinifyOutput
},
{
Expand Down Expand Up @@ -87,12 +114,25 @@ export function terserPlugin(config: ResolvedConfig): Plugin {
worker ||= makeWorker()

const terserPath = loadTerserPath(config.root)
const nth =
typeof terserOptions.mangle === 'object'
? { ...terserOptions.mangle.nth_identifier }
: undefined
if (nth) {
toString(nth, 'get')
toString(nth, 'consider')
toString(nth, 'sort')
}
const res = await worker.run(terserPath, code, {
safari10: true,
...terserOptions,
sourceMap: !!outputOptions.sourcemap,
module: outputOptions.format.startsWith('es'),
toplevel: outputOptions.format === 'cjs',
mangle:
typeof terserOptions.mangle === 'object'
? { ...terserOptions.mangle, nth_identifier: nth as any }
: terserOptions.mangle,
})
return {
code: res.code!,
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0d44fc5

Please sign in to comment.