diff --git a/packages/docs/vite.config.ts b/packages/docs/vite.config.ts index 6d039be3208b..59128ace9af3 100644 --- a/packages/docs/vite.config.ts +++ b/packages/docs/vite.config.ts @@ -128,6 +128,18 @@ export default defineConfig(async () => { Inspect(), qwikInsights({ publicApiKey: loadEnv('', '.', '').PUBLIC_QWIK_INSIGHTS_KEY }), ], + build: { + rollupOptions: { + onLog(level, log, defaultHandler) { + if (level == 'warn' && log.code === 'MODULE_LEVEL_DIRECTIVE') { + // Suppress errors like these: + // FILE Module level directives cause errors when bundled, "use client" in FILE was ignored. + return; + } + defaultHandler(level, log); + }, + }, + }, clearScreen: false, server: { port: 3000, diff --git a/packages/qwik-city/buildtime/vite/plugin.ts b/packages/qwik-city/buildtime/vite/plugin.ts index e0672304ae29..0e268206e86c 100644 --- a/packages/qwik-city/buildtime/vite/plugin.ts +++ b/packages/qwik-city/buildtime/vite/plugin.ts @@ -256,15 +256,15 @@ function qwikCityPlugin(userOpts?: QwikCityVitePluginOptions): any { closeBundle: { sequential: true, async handler() { - if (ctx?.target === 'ssr') { + if (ctx?.target === 'ssr' && !ctx?.isDevServer) { // ssr build const manifest = qwikPlugin!.api.getManifest(); const clientOutDir = qwikPlugin!.api.getClientOutDir(); - const insightsManifest = await qwikPlugin!.api.getInsightsManifest(clientOutDir); if (manifest && clientOutDir) { const basePathRelDir = api.getBasePathname().replace(/^\/|\/$/, ''); const clientOutBaseDir = join(clientOutDir, basePathRelDir); + const insightsManifest = await qwikPlugin!.api.getInsightsManifest(clientOutDir); for (const swEntry of ctx.serviceWorkers) { try { diff --git a/packages/qwik-labs/src-vite/insights/index.ts b/packages/qwik-labs/src-vite/insights/index.ts index ec7df840fd79..7176a85a3728 100644 --- a/packages/qwik-labs/src-vite/insights/index.ts +++ b/packages/qwik-labs/src-vite/insights/index.ts @@ -5,7 +5,13 @@ import { join } from 'node:path'; import { PluginOption } from 'vite'; const logWarn = (message?: any) => { - console.warn('\x1b[33m%s\x1b[0m', `\n\nQWIK WARN: ${message}\n`); + // eslint-disable-next-line no-console + console.warn('\x1b[33m%s\x1b[0m', `qwikInsight()[WARN]: ${message}`); +}; + +const log = (message?: any) => { + // eslint-disable-next-line no-console + console.log('\x1b[35m%s\x1b[0m', `qwikInsight(): ${message}`); }; export async function qwikInsights(qwikInsightsOpts: { @@ -22,6 +28,7 @@ export async function qwikInsights(qwikInsightsOpts: { const vitePlugin: PluginOption = { name: 'vite-plugin-qwik-insights', enforce: 'pre', + apply: 'build', async config(viteConfig) { isProd = viteConfig.mode !== 'ssr'; if (isProd) { @@ -36,7 +43,9 @@ export async function qwikInsights(qwikInsightsOpts: { if (!existsSync(join(process.cwd(), outDir))) { mkdirSync(join(process.cwd(), outDir), { recursive: true }); } - await writeFile(join(process.cwd(), outDir, 'q-insights.json'), JSON.stringify(qManifest)); + const cwdRelativePath = join(viteConfig.root || '.', outDir, 'q-insights.json'); + log('Fetched latest Qwik Insight data into: ' + cwdRelativePath); + await writeFile(join(process.cwd(), cwdRelativePath), JSON.stringify(qManifest)); } }, closeBundle: async () => { diff --git a/packages/qwik/src/optimizer/src/plugins/plugin.ts b/packages/qwik/src/optimizer/src/plugins/plugin.ts index 3bc6129e18cd..59d89c1544fd 100644 --- a/packages/qwik/src/optimizer/src/plugins/plugin.ts +++ b/packages/qwik/src/optimizer/src/plugins/plugin.ts @@ -304,7 +304,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { }; const buildStart = async (ctx: any) => { - log(`buildStart()`, opts.buildMode, opts.scope); + debug(`buildStart()`, opts.buildMode, opts.scope); const optimizer = getOptimizer(); if (optimizer.sys.env === 'node' && opts.target === 'ssr') { @@ -322,7 +322,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { let srcDir = '/'; if (typeof opts.srcDir === 'string') { srcDir = normalizePath(opts.srcDir); - log(`buildStart() srcDir`, opts.srcDir); + debug(`buildStart() srcDir`, opts.srcDir); } else if (Array.isArray(opts.srcInputs)) { optimizer.sys.getInputFiles = async (rootDir) => opts.srcInputs!.map((i) => { @@ -332,14 +332,14 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { }; return relInput; }); - log(`buildStart() opts.srcInputs (${opts.srcInputs.length})`); + debug(`buildStart() opts.srcInputs (${opts.srcInputs.length})`); } const vendorRoots = opts.vendorRoots; if (vendorRoots.length > 0) { - log(`vendorRoots`, vendorRoots); + debug(`vendorRoots`, vendorRoots); } - log(`transformedOutput.clear()`); + debug(`transformedOutput.clear()`); transformedOutputs.clear(); const mode = @@ -372,7 +372,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { const result = await optimizer.transformFs(transformOpts); for (const output of result.modules) { const key = normalizePath(path.join(srcDir, output.path)!); - log(`buildStart() add transformedOutput`, key, output.hook?.displayName); + debug(`buildStart() add transformedOutput`, key, output.hook?.displayName); transformedOutputs.set(key, [output, key]); ssrTransformedOutputs.set(key, [output, key]); if (output.hook) { @@ -398,7 +398,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { importer: string | undefined, ssrOpts?: { ssr?: boolean } ) => { - log(`resolveId()`, 'Start', id, importer); + debug(`resolveId()`, 'Start', id, importer); if (id.startsWith('\0')) { return; @@ -414,7 +414,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { } if (opts.resolveQwikBuild && id.endsWith(QWIK_BUILD_ID)) { - log(`resolveId()`, 'Resolved', QWIK_BUILD_ID); + debug(`resolveId()`, 'Resolved', QWIK_BUILD_ID); return { id: normalizePath(getPath().resolve(opts.rootDir, QWIK_BUILD_ID)), moduleSideEffects: false, @@ -422,7 +422,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { } if (id.endsWith(QWIK_CLIENT_MANIFEST_ID)) { - log(`resolveId()`, 'Resolved', QWIK_CLIENT_MANIFEST_ID); + debug(`resolveId()`, 'Resolved', QWIK_CLIENT_MANIFEST_ID); if (opts.target === 'lib') { return { id: id, @@ -449,7 +449,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { const ext = path.extname(importeePathId).toLowerCase(); if (ext in RESOLVE_EXTS) { importer = normalizePath(importer); - log(`resolveId("${importeePathId}", "${importer}")`); + debug(`resolveId("${importeePathId}", "${importer}")`); const parsedImporterId = parseId(importer); const dir = path.dirname(parsedImporterId.pathId); if (parsedImporterId.pathId.endsWith('.html') && !importeePathId.endsWith('.html')) { @@ -462,7 +462,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { : transformedOutputs.get(importeePathId); if (transformedOutput) { - log(`resolveId() Resolved ${importeePathId} from transformedOutputs`); + debug(`resolveId() Resolved ${importeePathId} from transformedOutputs`); return { id: importeePathId + parsedId.query, }; @@ -473,13 +473,13 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { const importeePathId = normalizePath(parsedId.pathId); const ext = path.extname(importeePathId).toLowerCase(); if (ext in RESOLVE_EXTS) { - log(`resolveId("${importeePathId}", "${importer}")`); + debug(`resolveId("${importeePathId}", "${importer}")`); const transformedOutput = isSSR ? ssrTransformedOutputs.get(importeePathId) : transformedOutputs.get(importeePathId); if (transformedOutput) { - log(`resolveId() Resolved ${importeePathId} from transformedOutputs`); + debug(`resolveId() Resolved ${importeePathId} from transformedOutputs`); return { id: importeePathId + parsedId.query, }; @@ -495,7 +495,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { } const isSSR = ssrOpts?.ssr ?? opts.target === 'ssr'; if (opts.resolveQwikBuild && id.endsWith(QWIK_BUILD_ID)) { - log(`load()`, QWIK_BUILD_ID, opts.buildMode); + debug(`load()`, QWIK_BUILD_ID, opts.buildMode); return { moduleSideEffects: false, code: getQwikBuildModule(isSSR, opts.target), @@ -503,7 +503,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { } if (id.endsWith(QWIK_CLIENT_MANIFEST_ID)) { - log(`load()`, QWIK_CLIENT_MANIFEST_ID, opts.buildMode); + debug(`load()`, QWIK_CLIENT_MANIFEST_ID, opts.buildMode); return { moduleSideEffects: false, code: await getQwikServerManifestModule(isSSR), @@ -516,7 +516,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { const transformedModule = isSSR ? ssrTransformedOutputs.get(id) : transformedOutputs.get(id); if (transformedModule) { - log(`load()`, 'Found', id); + debug(`load()`, 'Found', id); let code = transformedModule[0].code; if (opts.target === 'ssr') { @@ -568,7 +568,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { ) { const strip = opts.target === 'client' || opts.target === 'ssr'; const normalizedID = normalizePath(pathId); - log(`transform()`, 'Transforming', pathId); + debug(`transform()`, 'Transforming', pathId); let filePath = base; if (opts.srcDir) { @@ -697,7 +697,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { }; } - log(`transform()`, 'No Transforming', id); + debug(`transform()`, 'No Transforming', id); return null; }; @@ -752,13 +752,18 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { }); }; - const log = (...str: any[]) => { + const debug = (...str: any[]) => { if (opts.debug) { // eslint-disable-next-line no-console console.debug(`[QWIK PLUGIN: ${id}]`, ...str); } }; + const log = (...str: any[]) => { + // eslint-disable-next-line no-console + console.log(`[QWIK PLUGIN: ${id}]`, ...str); + }; + const onDiagnostics = (cb: (d: Diagnostic[], optimizer: Optimizer, srcDir: string) => void) => { diagnosticsCallback = cb; }; @@ -812,6 +817,7 @@ export const manifest = ${JSON.stringify(manifest)};\n`; getTransformedOutputs, init, load, + debug, log, normalizeOptions, normalizePath, diff --git a/packages/qwik/src/optimizer/src/plugins/vite.ts b/packages/qwik/src/optimizer/src/plugins/vite.ts index b1b85a430338..658c99741bf5 100644 --- a/packages/qwik/src/optimizer/src/plugins/vite.ts +++ b/packages/qwik/src/optimizer/src/plugins/vite.ts @@ -9,6 +9,7 @@ import type { QwikManifest, TransformModule, InsightManifest, + Path, } from '../types'; import { versions } from '../versions'; import { getImageSizeServer } from './image-size-server'; @@ -57,10 +58,24 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { async function loadQwikInsights(clientOutDir?: string | null): Promise { const sys = qwikPlugin.getSys(); + const cwdRelativePath = absolutePathAwareJoin( + sys.path, + rootDir || '.', + clientOutDir ?? 'dist', + 'q-insights.json' + ); + const path = absolutePathAwareJoin(sys.path, process.cwd(), cwdRelativePath); const fs: typeof import('fs') = await sys.dynamicImport('node:fs'); - const path = sys.path.join(process.cwd(), clientOutDir ?? 'dist', 'q-insights.json'); if (fs.existsSync(path)) { + qwikPlugin.log('Reading Qwik Insight data from: ' + cwdRelativePath); return JSON.parse(await fs.promises.readFile(path, 'utf-8')) as InsightManifest; + } else { + qwikPlugin.log( + 'Qwik Insight not found `' + + cwdRelativePath + + '`, skipping.\n' + + '\t\tConsider setting up https://qwik.builder.io/docs/labs/insights/ for better bundle optimization.' + ); } return null; } @@ -113,20 +128,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { viteCommand = viteEnv.command; isClientDevOnly = viteCommand === 'serve' && viteEnv.mode !== 'ssr'; - qwikPlugin.log(`vite config(), command: ${viteCommand}, env.mode: ${viteEnv.mode}`); - - if (sys.env === 'node' && !qwikViteOpts.entryStrategy) { - try { - const entryStrategy = await loadQwikInsights( - !qwikViteOpts.csr ? qwikViteOpts.client?.outDir : undefined - ); - if (entryStrategy) { - qwikViteOpts.entryStrategy = entryStrategy; - } - } catch (e) { - // ok to ignore - } - } + qwikPlugin.debug(`vite config(), command: ${viteCommand}, env.mode: ${viteEnv.mode}`); if (viteCommand === 'serve') { qwikViteOpts.entryStrategy = { type: 'hook' }; @@ -379,8 +381,21 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { return updatedViteConfig; }, - configResolved(config) { + async configResolved(config) { basePathname = config.base; + const sys = qwikPlugin.getSys(); + if (sys.env === 'node' && !qwikViteOpts.entryStrategy) { + try { + const entryStrategy = await loadQwikInsights( + !qwikViteOpts.csr ? qwikViteOpts.client?.outDir : undefined + ); + if (entryStrategy) { + qwikViteOpts.entryStrategy = entryStrategy; + } + } catch (e) { + // ok to ignore + } + } }, async buildStart() { @@ -628,7 +643,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { }, handleHotUpdate(ctx) { - qwikPlugin.log('handleHotUpdate()', ctx); + qwikPlugin.debug('handleHotUpdate()', ctx); for (const mod of ctx.modules) { const deps = mod.info?.meta?.qwikdeps; @@ -902,3 +917,19 @@ export interface QwikViteDevResponse { _qwikEnvData?: Record; _qwikRenderResolve?: () => void; } + +/** + * Joins path segments together and normalizes the resulting path, taking into account absolute + * paths. + */ +function absolutePathAwareJoin(path: Path, ...segments: string[]): string { + for (let i = segments.length - 1; i >= 0; --i) { + const segment = segments[i]; + if (segment.startsWith(path.sep) || segment.indexOf(path.delimiter) !== -1) { + segments.splice(0, i); + break; + } + } + return path.join(...segments); +} +