Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error using build.terserOptions mangle nth_identifier #17409

Closed
7 tasks done
farseekers opened this issue Jun 7, 2024 · 3 comments · Fixed by #18987 · May be fixed by #17589
Closed
7 tasks done

Error using build.terserOptions mangle nth_identifier #17409

farseekers opened this issue Jun 7, 2024 · 3 comments · Fixed by #18987 · May be fixed by #17589
Labels
p3-minor-bug An edge case that only affects very specific usage (priority)

Comments

@farseekers
Copy link

Describe the bug

I'm attempting to prefix mangled variable names.

https://vitejs.dev/config/build-options#build-terseroptions told me that under build.terserOptions, I could add

Additional minify options to pass on to Terser.

https://terser.org/docs/api-reference/#minify-options

mangle.properties (default false) — a subcategory of the mangle option. Pass an object to specify custom mangle property options.

https://terser.org/docs/options/#mangle-properties-options

nth_identifer (default: an internal mangler that weights based on character frequency analysis) -- Pass an object with a get(n) function that converts an ordinal into the nth most favored (usually shortest) identifier. Optionally also provide reset(), sort(), and consider(chars, delta) to use character frequency analysis of the source code.

So following that, I constructed the following (a minimal reproduction of it, anyway).

export default {
  build: {
    minify: 'terser',
    terserOptions: {
      mangle: {
        properties: {
          nth_identifier: {
            get: n => {
              return 'prefix_'+n.toString()
            }
          }
        }
      }
    }
  }
}

However, it fails to work, raising an error.

> vite v5.2.12 building for production...
> ✓ 1 modules transformed.
> x Build failed in 24ms
> error during build:
> Cannot set property code of  which has only a getter
>     at logPluginError (file:///reproduction/node_modules/rollup/dist/es/shared/parseAst.js:894:16)
>     at file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:19800:26
>     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
>     at async transformChunk (file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:17934:16)
>     at async file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:18008:17
>     at async Promise.all (index 0)
>     at async transformChunksAndGenerateContentHashes (file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:18003:5)
>     at async renderChunks (file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:17912:137)
>     at async Bundle.generate (file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:18145:13)
>     at async file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:20692:27

After removing two catches in the node modules to find the origin of the problem, I got

error during build:
DataCloneError: (n) => {
              return "prefix_" + n.toString();
            } could not be cloned.
    at new DOMException (node:internal/per_context/domexception:53:5)
    at Worker.postMessage (node:internal/worker:366:5)
    at file:///reproduction/node_modules/vite/dist/node/chunks/dep-BKbDVx1T.js:15135:14
    at new Promise (<anonymous>)
    at Worker.run (file:///reproduction/node_modules/vite/dist/node/chunks/dep-BKbDVx1T.js:15132:12)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Object.renderChunk (file:///reproduction/node_modules/vite/dist/node/chunks/dep-BKbDVx1T.js:15382:25)

Please let me know if I've missed something, as it would seem that the inability to clone a function is preventing this feature from working.

Reproduction

https://github.com/farseekers/terserOptions

Steps to reproduce

  1. npm install
  2. Terser works by itself - node index.js
  3. vite does not - ./node_modules/.bin/vite build, raising an error

System Info

System:
    OS: macOS 14.5
    CPU: (8) arm64 Apple M1
    Memory: 137.39 MB / 8.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.20.3 - /opt/local/bin/node
    Yarn: 1.22.22 - /opt/local/bin/yarn
    npm: 8.19.4 - /opt/local/bin/npm
    pnpm: 9.0.5 - /opt/local/bin/pnpm
  Browsers:
    Brave Browser: 125.1.66.118
    Chrome: 125.0.6422.142
    Safari: 17.5

Used Package Manager

npm

Logs

vite v5.2.12 building for production...
✓ 1 modules transformed.
x Build failed in 24ms
error during build:
Cannot set property code of which has only a getter
at logPluginError (file:///reproduction/node_modules/rollup/dist/es/shared/parseAst.js:894:16)
at file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:19800:26
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async transformChunk (file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:17934:16)
at async file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:18008:17
at async Promise.all (index 0)
at async transformChunksAndGenerateContentHashes (file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:18003:5)
at async renderChunks (file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:17912:137)
at async Bundle.generate (file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:18145:13)
at async file:///reproduction/node_modules/rollup/dist/es/shared/node-entry.js:20692:27

Validations

@bluwy
Copy link
Member

bluwy commented Jun 10, 2024

Seems like it's because we run terser with a worker, and the options can't be properly serialized. We should definitely fix and provide a better error message, but for the serialization it's not always possible to assume that a function is isolated for serializing. I guess the solution would be either:

  1. Like CSS preprocessing, maybe we could have a fallback mode that runs on the current thread if there's no serializable values, but that may make things slower.
  2. Or force serialize functions and require the definition to always be isolated.
  3. Or some sort of custom serializer option.

@farseekers
Copy link
Author

Thanks very much for the confirmation that I wasn't missing something.

@wmertens
Copy link
Contributor

@bluwy this option is needed to have consistent names between builds so that chunks stay the same as much as possible, thereby reducing traffic.

Can't you assume that if a function is passed, it is self-contained?

Failing that, how about a special option type where you can provide source code to eval?

@sapphi-red sapphi-red added the p3-minor-bug An edge case that only affects very specific usage (priority) label Dec 17, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Jan 1, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
p3-minor-bug An edge case that only affects very specific usage (priority)
Projects
None yet
4 participants