Skip to content

Commit b1330cb

Browse files
committed
fix(router,core): provide router meta files during build
also remove the workaround that we needed in core for chunk filenames
1 parent 4811307 commit b1330cb

File tree

3 files changed

+91
-70
lines changed

3 files changed

+91
-70
lines changed

.changeset/many-tips-win.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@qwik.dev/core': minor
3+
'@qwik.dev/router': patch
4+
---
5+
6+
FEAT: Server output chunk files are now under their own build/ subdir, like the client build. This makes it easier to override the chunk filenames. This is possible because the Router metadata files are now an earlier part of the build process.

packages/qwik-router/src/buildtime/vite/plugin.ts

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ function qwikRouterPlugin(userOpts?: QwikRouterVitePluginOptions): any {
7171

7272
type P<T> = Plugin<T> & { api: T };
7373

74+
let didEmitStaticPaths = false;
75+
let didEmitNotFoundPaths = false;
76+
7477
const plugin: P<QwikRouterPluginApi> = {
7578
name: 'vite-plugin-qwik-router',
7679
enforce: 'pre',
@@ -164,6 +167,8 @@ function qwikRouterPlugin(userOpts?: QwikRouterVitePluginOptions): any {
164167
},
165168

166169
buildStart() {
170+
didEmitStaticPaths = false;
171+
didEmitNotFoundPaths = false;
167172
resetBuildContext(ctx);
168173
},
169174

@@ -183,17 +188,29 @@ function qwikRouterPlugin(userOpts?: QwikRouterVitePluginOptions): any {
183188
if (id === QWIK_ROUTER_SW_REGISTER) {
184189
return join(rootDir!, id);
185190
}
186-
if (id === STATIC_PATHS_ID) {
187-
return {
188-
id: './' + RESOLVED_STATIC_PATHS_ID,
189-
external: true,
190-
};
191+
if (id.endsWith(STATIC_PATHS_ID)) {
192+
const resolvedId = 'virtual:' + RESOLVED_STATIC_PATHS_ID;
193+
if (!didEmitStaticPaths) {
194+
this.emitFile({
195+
type: 'chunk',
196+
fileName: RESOLVED_STATIC_PATHS_ID,
197+
id,
198+
});
199+
didEmitStaticPaths = true;
200+
}
201+
return { id: resolvedId };
191202
}
192-
if (id === NOT_FOUND_PATHS_ID) {
193-
return {
194-
id: './' + RESOLVED_NOT_FOUND_PATHS_ID,
195-
external: true,
196-
};
203+
if (id.endsWith(NOT_FOUND_PATHS_ID)) {
204+
const resolvedId = 'virtual:' + RESOLVED_NOT_FOUND_PATHS_ID;
205+
if (!didEmitNotFoundPaths) {
206+
this.emitFile({
207+
type: 'chunk',
208+
fileName: RESOLVED_NOT_FOUND_PATHS_ID,
209+
id,
210+
});
211+
didEmitNotFoundPaths = true;
212+
}
213+
return { id: resolvedId };
197214
}
198215
return null;
199216
},
@@ -205,12 +222,11 @@ function qwikRouterPlugin(userOpts?: QwikRouterVitePluginOptions): any {
205222
return generateQwikRouterEntries(ctx);
206223
}
207224
const isSerializer = id.endsWith(QWIK_SERIALIZER);
208-
const isRouterConfig = id.endsWith(QWIK_ROUTER_CONFIG_ID);
209-
const isSwRegister = id.endsWith(QWIK_ROUTER_SW_REGISTER);
210-
211225
if (isSerializer) {
212226
return `export {_deserialize, _serialize, _verifySerializable} from '@qwik.dev/core'`;
213227
}
228+
const isRouterConfig = id.endsWith(QWIK_ROUTER_CONFIG_ID);
229+
const isSwRegister = id.endsWith(QWIK_ROUTER_SW_REGISTER);
214230
if (isRouterConfig || isSwRegister) {
215231
if (!ctx.isDevServer && ctx.isDirty) {
216232
await build(ctx);
@@ -232,6 +248,15 @@ function qwikRouterPlugin(userOpts?: QwikRouterVitePluginOptions): any {
232248
}
233249
}
234250
}
251+
// These files are overwritten in post-build.ts
252+
const isStaticPaths = id.endsWith(RESOLVED_STATIC_PATHS_ID);
253+
if (isStaticPaths) {
254+
return `export const isStaticPath = () => false`;
255+
}
256+
const isNotFoundPathsId = id.endsWith(RESOLVED_NOT_FOUND_PATHS_ID);
257+
if (isNotFoundPathsId) {
258+
return `export const getNotFound = () => {}`;
259+
}
235260
return null;
236261
},
237262

packages/qwik/src/optimizer/src/plugins/rollup.ts

Lines changed: 47 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,35 @@ export function normalizeRollupOutputOptions(
151151
};
152152
}
153153

154+
const getChunkFileName = (
155+
prefix: string,
156+
opts: NormalizedQwikPluginOptions,
157+
optimizer: Optimizer
158+
) => {
159+
if (opts.buildMode === 'production' && !opts.debug) {
160+
return `${prefix}build/q-[hash].js`;
161+
} else {
162+
// Friendlier names in dev or preview with debug mode
163+
return (chunkInfo: Rollup.PreRenderedChunk) => {
164+
if (chunkInfo.moduleIds?.some((id) => id.endsWith('core.prod.mjs'))) {
165+
return `${prefix}build/core.js`;
166+
}
167+
if (chunkInfo.moduleIds?.some((id) => id.endsWith('qwik-router/lib/index.qwik.mjs'))) {
168+
return `${prefix}build/qwik-router.js`;
169+
}
170+
171+
// The chunk name can often be a path. We sanitize it to use dashes instead of slashes, to keep the same folder structure as without debug:true.
172+
// Besides, Rollup doesn't accept absolute or relative paths as inputs for the [name] placeholder for the same reason.
173+
const relativePath = optimizer.sys.path.relative(optimizer.sys.cwd(), chunkInfo.name);
174+
const sanitized = relativePath
175+
.replace(/^(\.\.\/)+/, '')
176+
.replace(/^\/+/, '')
177+
.replace(/\//g, '-');
178+
return `${prefix}build/${sanitized}.js`;
179+
};
180+
}
181+
};
182+
154183
export function normalizeRollupOutputOptionsObject(
155184
qwikPlugin: QwikPlugin,
156185
rollupOutputOptsObj: Rollup.OutputOptions | undefined,
@@ -160,79 +189,40 @@ export function normalizeRollupOutputOptionsObject(
160189
const opts = qwikPlugin.getOptions();
161190
const optimizer = qwikPlugin.getOptimizer();
162191
const manualChunks = qwikPlugin.manualChunks;
163-
if (opts.target === 'client') {
164-
// client output
165-
if (!outputOpts.assetFileNames) {
166-
// SEO likes readable asset names
167-
const assetFileNames = 'assets/[hash]-[name].[ext]';
168-
outputOpts.assetFileNames = useAssetsDir
169-
? `${opts.assetsDir}/${assetFileNames}`
170-
: assetFileNames;
171-
}
172192

173-
let fileName: string | ((chunkInfo: Rollup.PreRenderedChunk) => string) | undefined;
174-
if (opts.buildMode === 'production' && !opts.debug) {
175-
fileName = 'build/q-[hash].js';
176-
} else {
177-
// Friendlier names in dev or preview with debug mode
178-
fileName = (chunkInfo) => {
179-
if (chunkInfo.moduleIds?.some((id) => id.endsWith('core.prod.mjs'))) {
180-
return 'build/core.js';
181-
}
182-
if (chunkInfo.moduleIds?.some((id) => id.endsWith('qwik-router/lib/index.qwik.mjs'))) {
183-
return 'build/qwik-router.js';
184-
}
185-
186-
// The chunk name can often be a path. We sanitize it to use dashes instead of slashes, to keep the same folder structure as without debug:true.
187-
// Besides, Rollup doesn't accept absolute or relative paths as inputs for the [name] placeholder for the same reason.
188-
const path = optimizer.sys.path;
189-
const relativePath = path.relative(optimizer.sys.cwd(), chunkInfo.name);
190-
const sanitized = relativePath
191-
.replace(/^(\.\.\/)+/, '')
192-
.replace(/^\/+/, '')
193-
.replace(/\//g, '-');
194-
return `build/${sanitized}.js`;
195-
};
196-
}
197-
// client development/debug output
198-
const getFilePath = (fileNamePattern: string | ((info: Rollup.PreRenderedChunk) => string)) =>
199-
typeof fileNamePattern === 'string'
200-
? useAssetsDir
201-
? `${opts.assetsDir}/${fileNamePattern}`
202-
: fileNamePattern
203-
: useAssetsDir
204-
? (chunkInfo: Rollup.PreRenderedChunk) =>
205-
`${opts.assetsDir}/${fileNamePattern(chunkInfo)}`
206-
: (chunkInfo: Rollup.PreRenderedChunk) => fileNamePattern(chunkInfo);
193+
if (!outputOpts.assetFileNames) {
194+
// SEO likes readable asset names
195+
// assetsDir allows assets to be in a deeper directory for serving, e.g. Astro
196+
outputOpts.assetFileNames = `${useAssetsDir ? `${opts.assetsDir}/` : ''}assets/[hash]-[name].[ext]`;
197+
}
207198

199+
const chunkFileName = getChunkFileName(useAssetsDir ? `${opts.assetsDir}` : '', opts, optimizer);
200+
if (opts.target === 'client') {
201+
// client output
208202
if (!outputOpts.entryFileNames) {
209-
outputOpts.entryFileNames = getFilePath(fileName);
203+
// we don't treat entries specially for the client
204+
outputOpts.entryFileNames = chunkFileName;
210205
}
211206
if (!outputOpts.chunkFileNames) {
212-
outputOpts.chunkFileNames = getFilePath(fileName);
207+
outputOpts.chunkFileNames = chunkFileName;
213208
}
214-
} else if (opts.buildMode === 'production') {
215-
// server production output
216-
// everything in same dir so './@qwik-router...' imports work from entry and chunks
217-
if (!outputOpts.chunkFileNames) {
218-
outputOpts.chunkFileNames = 'q-[hash].js';
219-
}
220-
}
221-
// all other cases, like lib output
222-
if (!outputOpts.assetFileNames) {
223-
outputOpts.assetFileNames = 'assets/[hash]-[name].[ext]';
224-
}
225209

226-
if (opts.target === 'client') {
227210
// client should always be es
228211
outputOpts.format = 'es';
229212
const prevManualChunks = outputOpts.manualChunks;
230213
if (prevManualChunks && typeof prevManualChunks !== 'function') {
231214
throw new Error('manualChunks must be a function');
232215
}
216+
217+
// We need custom chunking for the client build
233218
outputOpts.manualChunks = prevManualChunks
234219
? (id, meta) => prevManualChunks(id, meta) || manualChunks(id, meta)
235220
: manualChunks;
221+
} else {
222+
// server production output, try to be similar to client
223+
if (!outputOpts.chunkFileNames) {
224+
outputOpts.chunkFileNames = chunkFileName;
225+
}
236226
}
237227

238228
if (!outputOpts.dir) {

0 commit comments

Comments
 (0)