-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
[🐞] build.client doesn't care about previous chunks when the update of the app. #7226
Comments
Hi @genki with the same code the hash should remain the same. If not we need to figure out the why. If you need to preserve the old chunks too you can implement a Vite plugin that read and write them somewhere to preserve them during builds. Btw this could be a Qwik community plugin. |
Another solution cloud be: a Vite plugin that download all the current chunks locally ( based on q-manifest ) and merge them after the build process |
@gioboa Thank you for the answer. I wonder why the change happens to q-manifest.json and chunks even if no updates in my source code. Of course, no dynamic
There are many chunks built, but most of them are very small and only consists of imports other chunks and one export like this. import"./q-CLq9cP0Z.js";import{c as N}from"./q-TmSm9_Ab.js";import"./q-iUhm9qIU.js";import"./q-CDfZr0w7.js";import"./q-BVGg7BBr.js";import"./q-CT7XUfUO.js";export{N as s_BdTzVN1StNM}; And these chunks that are imported here are also changed while the build 1 and 2. As I understood this is something wrong I would investigate more. |
Ah, I have one more question. Such the piles of small code snippets that are consist of only imports and one export is expected behaviour?.
I don't provide any customization to rollup options. |
Here is my const WIDTHS = [640, 1024];
export default defineConfig(():UserConfig => {
return {
plugins: [
qwikCity(),
qwikVite(),
tsconfigPaths(),
],
ssr: {
external: ['node:async_hooks'],
},
preview: {
headers: {
"Cache-Control": "public, max-age=600",
"X-Content-Type-Options": "nosniff",
},
},
resolve: {
alias: {
"~": path.resolve(__dirname, "src"),
},
},
css: {
preprocessorOptions: {
sass: {
additionalData: `$widths: ${WIDTHS.map(w => w + "px").join(",")}\n`,
},
},
},
};
}); |
I guess so, can you try to create a small reproduction repo to figure out the situation and solve the issue please? |
@gioboa Yeah, I think so too. I have tried with no luck. If get success, I will come back :) |
Further investigation about the output, I found the cyclic import between Chunk: const RouteStateContext = /* @__PURE__ */ createContextId("qc-s");
const ContentContext = /* @__PURE__ */ createContextId("qc-c");
const ContentInternalContext = /* @__PURE__ */ createContextId("qc-ic");
const DocumentHeadContext = /* @__PURE__ */ createContextId("qc-h");
const RouteLocationContext = /* @__PURE__ */ createContextId("qc-l");
const RouteNavigateContext = /* @__PURE__ */ createContextId("qc-n");
const RouteActionContext = /* @__PURE__ */ createContextId("qc-a");
const RouteInternalContext = /* @__PURE__ */ createContextId("qc-ir");
const RoutePreventNavigateContext = /* @__PURE__ */ createContextId("qc-p");
const spaInit = eventQrl(/* @__PURE__ */ qrl(() => __vitePreload(() => import("./q-4Y1X7MJF.js"), true ? [] : void 0), "s_o0fE7sdgJro"));
const RouterOutlet = /* @__PURE__ */ componentQrl(/* @__PURE__ */ qrl(() => __vitePreload(() => import("./q-C6SJWZkU.js"), true ? [] : void 0), "s_0rmCF5rEoas")); The last line dynamic imports the RouterOutlet. The imported code is importing it back circulary at the 1st line. Chunk: import { B as spaInit, d as ContentInternalContext } from "./q-D9K9vuh1.js";
import { a as useServerData, C as _jsxBranch, u as useContext, l as _jsxC, f as _jsxQ, p as _qrlSync, F as Fragment, D as SkipRender } from "./q-Bf_tcDXr.js";
const s_0rmCF5rEoas = () => {
const serverData = useServerData("containerAttributes");
if (!serverData) throw new Error("PrefetchServiceWorker component must be rendered on the server.");
_jsxBranch();
const context = useContext(ContentInternalContext);
if (context.value && context.value.length > 0) {
const contentsLen = context.value.length;
let cmp = null;
for (let i = contentsLen - 1; i >= 0; i--) if (context.value[i].default) cmp = _jsxC(context.value[i].default, {
children: cmp
}, 1, "Ms_0");
return /* @__PURE__ */ _jsxC(Fragment, {
children: [
cmp,
/* @__PURE__ */ _jsxQ("script", {
"document:onQCInit$": spaInit,
"document:onQInit$": _qrlSync(() => {
((w, h) => {
var _a;
if (!w._qcs && h.scrollRestoration === "manual") {
w._qcs = true;
const s = (_a = h.state) == null ? void 0 : _a._qCityScroll;
if (s) w.scrollTo(s.x, s.y);
document.dispatchEvent(new Event("qcinit"));
}
})(window, history);
}, '()=>{((w,h)=>{if(!w._qcs&&h.scrollRestoration==="manual"){w._qcs=true;const s=h.state?._qCityScroll;if(s){w.scrollTo(s.x,s.y);}document.dispatchEvent(new Event("qcinit"));}})(window,history);}')
}, null, null, 2, "Ms_1")
]
}, 1, "Ms_2");
}
return SkipRender;
};
export {
s_0rmCF5rEoas
}; At least those two chunks can't be exist stably because the hash can't be computed. I guess the Vite would probably roughly solve this deadlock by choosing a random hash for such the chunks. |
The why only the larger app cause this issue is maybe those two chunks are not splitted in a smaller apps. |
Relating to vitejs/vite#10636 |
We definitely need to solve this cc @wmertens |
@gioboa @wmertens But finally, I have found the threshold of the fail and success. Alas, the nonce is random value. |
At any rate, the nonce is not the only reason of this issue. |
I wrote a vite pluting that merges previous build into import type {Plugin} from 'vite';
import fs from 'fs';
import path from 'path';
const CUR_BUILD = path.resolve(process.cwd(), 'current');
type Options = {
expireDuration?: number; // in seconds
}
export function mergeBuild({expireDuration}:Options = {}): Plugin {
const now = Date.now();
let count = 0;
let size = 0;
return {
name: 'merge-build',
enforce: 'pre',
generateBundle: {
order: "pre",
handler() {
console.log('merge-build copying files...');
const dist = path.resolve(process.cwd(), 'dist');
if (!fs.existsSync(dist)) fs.mkdirSync(dist);
const distBuild = path.resolve(dist, 'build');
if (!fs.existsSync(distBuild)) fs.mkdirSync(distBuild);
// copy current build into distBuild dir wiout change ctime/mtime
const curBuild = fs.readdirSync(CUR_BUILD);
for (const file of curBuild) {
const src = path.resolve(CUR_BUILD, file);
const dst = path.resolve(distBuild, file);
if (fs.existsSync(dst)) continue;
const stats = fs.statSync(src);
// check if file is not expired
if (expireDuration !== undefined) {
if (now - stats.mtimeMs > expireDuration * 1000) continue;
}
fs.copyFileSync(src, dst);
// copy ctime/mtime
fs.utimesSync(dst, stats.atime, stats.mtime);
count++;
size += stats.size;
}
}
},
closeBundle() {
const prettySize = (size / 1024).toFixed(2) + 'kB';
console.log("merge-build:", count, "files", prettySize,
"merged from previous build");
}
};
} |
Thanks, that's nice 🥳 |
Sorry I am not good at natural languages other than Japanese. |
Ok, can you try to modify the plugin to work on CI/CD pipeline env? ( reading and fetching the production chunks ) |
Which component is affected?
Qwik Rollup / Vite plugin
Describe the bug
I am writing somewhat large app with Qwik and when I tried to update it, the
pnpm run build.client
generates about 500-600 chunks but they have almost different hash from the previous output.When I would take a rolling update of the app, the existing app running in the browser experiences failure of dynamic import against the previous chunks, because they are no longer exist at that place after the update.
I wanted to make the experience seamless during the app update.
How can I include the previous chunks into the newly generated ones and merge the newer and older
q-manifest
?Reproduction
It's difficult to provide
Steps to reproduce
No response
System Info
Additional Information
In addition, when the app size is larger, the
pnpm run build.client
generates almost different hashes even if there's no changes in the source code. Is this expected behaviour?The text was updated successfully, but these errors were encountered: