Skip to content

Commit cd0340b

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 c5c438e commit cd0340b

File tree

2 files changed

+85
-70
lines changed

2 files changed

+85
-70
lines changed

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)