vite
vite copied to clipboard
Non-deterministic build
Describe the bug
Executing builds multiple times with the same code generates different hashes.
Reproduction
https://github.com/ttionya/vite-non-deterministic-build-repro
Steps to reproduce
Clone the aforementioned repro, install dependencies, and execute npm run build
multiple times. Verify the hash of the vendor file.
System Info
System:
OS: Windows 10 10.0.19045
CPU: (8) x64 Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz
Memory: 3.92 GB / 15.76 GB
Binaries:
Node: 14.21.0
npm: 9.6.7
Browsers:
Edge: Spartan (44.19041.1266.0), Chromium (114.0.1823.58)
Internet Explorer: 11.0.19041.1566
npmPackages:
@vitejs/plugin-legacy: ^4.0.0 => 4.0.1
@vitejs/plugin-vue2: ^2.2.0 => 2.2.0
@vitejs/plugin-vue2-jsx: ^1.1.0 => 1.1.0
vite: ^4.3.8 => 4.3.8
Used Package Manager
npm
Logs
No response
Validations
- [X] Follow our Code of Conduct
- [X] Read the Contributing Guidelines.
- [X] Read the docs.
- [X] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [X] Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to vuejs/core instead.
- [X] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- [X] The provided reproduction is a minimal reproducible example of the bug.
I'm aware of two similar issues. One is #11911, but it is unrelated to this issue. The other one #13071 might be relevant, but even after commenting on it 10 days ago, I haven't received any response. Therefore, I have created a new issue and provided a reproducible repository.
I have written a plugin that prints all the parameters in the transform hook. During two consecutive builds, although the order of their outputs is different, I found that there is only one instance where the content of the output differs after adjusting the order.
plugins: [
function() {
return {
name: 'test',
transform: (...args) => {
console.log(args)
}
}
}()
]
I have removed a significant amount of irrelevant code, so the hash of the artifact is different from the one in the repro.
First build:
[
'export { __moduleExports as default } from "C:/Users/admin/Projects/My/vite-non-deterministic-build-repro/node_modules/dayjs/dayjs.min.js";',
'\x00C:/Users/admin/Projects/My/vite-non-deterministic-build-repro/node_modules/dayjs/dayjs.min.js?commonjs-proxy'
]
[2mdist/[22m[36massets/index-e2988d1d.js [39m[1m[2m 1.10 kB[22m[1m[22m[2m │ gzip: 0.63 kB[22m
[2mdist/[22m[36massets/vendor-3bedaa96.js [39m[1m[2m81.22 kB[22m[1m[22m[2m │ gzip: 32.73 kB[22m
[32m✓ built in 1.97s[39m
Second build:
[
'import { getDefaultExportFromCjs } from "\x00commonjsHelpers.js";\n' +
'import { __require as requireDayjs_min } from "C:/Users/admin/Projects/My/vite-non-deterministic-build-repro/node_modules/dayjs/dayjs.min.js";\n' +
'var dayjs_minExports = requireDayjs_min();\n' +
'export { dayjs_minExports as __moduleExports };export default /*@__PURE__*/getDefaultExportFromCjs(dayjs_minExports);',
'\x00C:/Users/admin/Projects/My/vite-non-deterministic-build-repro/node_modules/dayjs/dayjs.min.js?commonjs-es-import'
]
[2mdist/[22m[36massets/index-73275ff8.js [39m[1m[2m 1.10 kB[22m[1m[22m[2m │ gzip: 0.63 kB[22m
[2mdist/[22m[36massets/vendor-2f895bab.js [39m[1m[2m81.26 kB[22m[1m[22m[2m │ gzip: 32.75 kB[22m
[32m✓ built in 2.97s[39m
Facing the same issue! waiting for a fix.
I'm seeing this issue as well.
The workaround mentioned in #10506, setting maxParallelFileOps: 1
, has seemed to resolve this for me.
The workaround in #10506 doesn't seem to work for me. I created a repo to try testing the workaround using the basic out-of-the-box base sveltekit app. Test repo is here https://github.com/derheld42/repro-vite-10506
Seems like dayjs
is seen as commonjs, and there's a related upstream bug: https://github.com/rollup/plugins/issues/1425
Thanks for the simple repro (and sorry for not responding in the other issue). Got a few issues to juggle, but I'll try to check this deeper now to see if there's something that can be fixed.
Also as explained in the upstream issue, the workaround would be:
export default defineConfig({
build: {
commonjsOptions: {
strictRequires: true
}
}
})
I tried the workaround in the above comment and it didn't create a deterministic build for me. I also tested it with https://github.com/derheld42/repro-vite-10506/commit/a31754f1e6af53096a76cf76944139f98e9d38ae and it doesn't produce a deterministic build.
@derheld42 that seems to be a SvelteKit specific issue: https://github.com/sveltejs/kit/issues/8948
You can fix it with:
const config = {
kit: {
version: {
name: 'test' // something stable instead of default `Date.now()`
}
}
};
After adding strictRequires
option for the repro, it consistently generates a deterministic hash on every build, which looks great.
After adding the strictRequires
option to my larger project, the significant build differences that existed previously have disappeared, except for the polyfill-legacy-[hash].js
(generated by @vitejs/plugin-legacy
). I spent some time trying to find a way to reproduce the instability in building the polyfill, but unfortunately, I failed. It appears that it doesn't stem from a singular syntax, so despite numerous attempts, I couldn't yield any results. I'm aware that a simple description won't be of any help in troubleshooting the issue, so this is just a record for now. Perhaps, if I manage to find a way to reproduce it in the future, I'll return to provide an update.
@derheld42 that seems to be a SvelteKit specific issue: sveltejs/kit#8948
You can fix it with:
const config = { kit: { version: { name: 'test' // something stable instead of default `Date.now()` } } };
Yes - that worked to make the built files deterministic - thank you!
I'm also facing the same issue, strictRequires
didn't work for me.
Here is my dependencies, can anyone give me any hint which is causing this.
"devDependencies": {
"@builder.io/qwik": "^1.2.15",
"@builder.io/qwik-city": "^1.2.15",
"@fastify/compress": "^6.2.1",
"@fastify/http-proxy": "^9.2.1",
"@fastify/static": "^6.10.1",
"@fullhuman/postcss-purgecss": "^5.0.0",
"@types/eslint": "8.44.1",
"@types/js-cookie": "^3.0.4",
"@types/lodash": "^4.14.199",
"@types/node": "^20.4.5",
"@typescript-eslint/eslint-plugin": "6.2.0",
"@typescript-eslint/parser": "6.2.0",
"autoprefixer": "^10.4.14",
"country-flag-icons": "^1.5.7",
"cssnano": "^6.0.1",
"eslint": "8.45.0",
"eslint-plugin-qwik": "^1.2.12",
"fastify": "^4.17.0",
"fastify-plugin": "^4.5.0",
"postcss": "8.4.27",
"postcss-import": "^15.1.0",
"postcss-nested": "^6.0.1",
"prettier": "3.0.0",
"purgecss": "^5.0.0",
"tailwindcss": "3.3.3",
"tw-elements": "1.0.0-alpha13",
"typescript": "5.1.6",
"undici": "5.22.1",
"vite": "4.4.7",
"vite-plugin-static-copy": "^0.17.0",
"vite-plugin-thumbhash-base64": "^0.0.2",
"vite-tsconfig-paths": "4.2.0"
},
"dependencies": {
"@fontsource-variable/dm-sans": "^5.0.3",
"@fontsource/dm-sans": "^5.0.14",
"@iconscout/unicons": "^4.0.8",
"@modular-forms/qwik": "^0.21.0",
"@svgx/vite-plugin-qwik": "^1.0.1",
"animate.css": "^4.1.1",
"date-fns": "^2.30.0",
"dayjs": "^1.11.10",
"flowbite": "^1.8.1",
"js-base64": "^3.7.5",
"js-cookie": "^3.0.5",
"libphonenumber-js": "^1.10.47",
"lodash": "^4.17.21",
"moick-qwik-fixed": "^1.0.6",
"qwik-content-loader": "^0.0.2",
"qwik-scroll-to-top": "^0.0.7",
"qwik-select-fixed": "^0.0.4",
"valibot": "^0.19.0",
"zod": "^3.22.4"
}
We're having this issue as well (even with the workarounds I've seen listed) which is very frustrating. Will this be addressed soon?
Here is our vite.config.js; I welcome any suggestions for additional things to try:
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
laravel({
input: ['resources/js/app.tsx'],
refresh: true,
}),
react(),
],
build: {
rollupOptions: {
// Suggested here for DETERMINISTIC BUILD: https://github.com/vitejs/vite/issues/10506 (from https://github.com/vitejs/vite/issues/13672)
maxParallelFileOps: 1,
},
// Suggested here for DETERMINISTIC BUILD: https://github.com/vitejs/vite/issues/13672#issuecomment-1784110536
commonjsOptions: {
strictRequires: true
}
}
});
facing the issue with the react component that is not chaging at all, but hash is new all the time
I have a pretty detailed example in https://github.com/vitejs/vite/discussions/15994.
It seems that the suggestions in this thread helped. I'm guessing that it was the CommonJS strictRequires: true
that helped, mainly because my project is using CodemIrror5 which, AFAIK, is a complex CommonJS package.
Solutions mentioned here didn’t work for me. Each consecutive build without changes to source code produces new hashes for the same chunks and in some cases can lead to cascading cache invalidation issues which is really bad for performance.
Each consecutive build without changes to source code produces new hashes for the same chunks and in some cases can lead to cascading cache invalidation issues which is really bad for performance
We're seeing the exact same thing. Why wouldn't the hashes just be based solely on the content of the file being hashed? Or is the issue that there is non-determinism in the bundling process which makes for different content every time?
Or is the issue that there is non-determinism in the bundling process which makes for different content every time?
I think this is the main reason for this, and it seems like it should be fixed with build.commonjsOptions.strictRequires = true
, but it isn’t.
I have tried adding both workarounds to my code (strictRequires: true
and maxParallelFileOps: 1
) but neither helped; I am still seeing the same problem as others have noted here.
But here is a fun fact that may help someone isolate the cause further:
(a) when I run vite build
locally on my Mac then it works correctly--if I run it a second time, the hash is always the same!
(b) when I run in CI (we are using https://concourse-ci.org/) then the problem always occurs (but just for my JS files; I am getting constant hashes for my CSS files). The CSS files are quite a bit smaller than the JS files, which perhaps makes a difference.
vite: version 4.5.2
rollup: version 3.29.4
~@msorens we are seeing the same behavior you are: deterministic results locally on a Mac, different hashes in CI, but only non-deterministic for JS outputs, CSS is consistent.~
For us the issue turned out to be the Sentry Vite plugin's default behavior, which injects a helper method that makes the build result non-deterministic.
Analyzing the code a bit, I understood that this happens because the name of the index file changes, and it is imported in almost all other .js files. So, for the hash to work correctly, I imagine that this needs to be ignored in some way.
@devsuperfrete yes also mentioned that, if something is change at any place all hashes are affected, the reason is that everything included into index
Same here. strictRequires: true
doesn't work for us. And we urgently hope this issue can be resolved ASAP.
I found that the export order is different every time, which causes the difference, but I don't know how to fix it.
@geoffharcourt For us the issue turned out to be the Sentry Vite plugin's default behavior, which injects a helper method that makes the build result non-deterministic.
Could you share some more info on this? Looks like my code base uses that plugin. How/where did you find info about that injected helper method?
Hi @msorens this was painful for us, but we found this option and set it to false
: https://www.npmjs.com/package/@sentry/vite-plugin#releaseinject
Thanks, @geoffharcourt , I will give that a try. Not terribly familiar with Sentry: what is the impact of setting that option to false? Seems like it might not be able to manage builds as effectively...?
Thanks, @geoffharcourt , I will give that a try. Not terribly familiar with Sentry: what is the impact of setting that option to false? Seems like it might not be able to manage builds as effectively...?
It helps Sentry link exceptions to source. We found in our app that Sentry was still able to do it well without the helper injected.
We had the same issue with SvelteKit. They generate a version that is based on the current timestamp (which is something they discourage in their docs). Overriding the version as explained in their docs fixed the issue for us, even with the Sentry plugin's default config.
After adding
strictRequires
option for the repro, it consistently generates a deterministic hash on every build, which looks great.After adding the
strictRequires
option to my larger project, the significant build differences that existed previously have disappeared, except for thepolyfill-legacy-[hash].js
(generated by@vitejs/plugin-legacy
). I spent some time trying to find a way to reproduce the instability in building the polyfill, but unfortunately, I failed. It appears that it doesn't stem from a singular syntax, so despite numerous attempts, I couldn't yield any results. I'm aware that a simple description won't be of any help in troubleshooting the issue, so this is just a record for now. Perhaps, if I manage to find a way to reproduce it in the future, I'll return to provide an update.
Hi, I also met this where the generated polyfill bundle is not stable. I've opened the #16505, hopefully solving your problem.
@derheld42 that seems to be a SvelteKit specific issue: sveltejs/kit#8948 You can fix it with:
const config = { kit: { version: { name: 'test' // something stable instead of default `Date.now()` } } };
Yes - that worked to make the built files deterministic - thank you!
Worked. Thank you!