UNPKG

vike

Version:

The Framework *You* Control - Next.js & Nuxt alternative for unprecedented flexibility and dependability.

258 lines (257 loc) 11.7 kB
import '../../assertEnvVite.js'; export { pluginDistFileNames }; // Attempt to preserve file structure of `.page.js` files: // - https://github.com/vikejs/vike/commit/11a4c49e5403aa7c37c8020c462b499425b41854 // - Blocker: https://github.com/rollup/rollup/issues/4724 import { assert, assertUsage } from '../../../../utils/assert.js'; import { isArray } from '../../../../utils/isArray.js'; import { isCallable } from '../../../../utils/isCallable.js'; import { assertPosixPath } from '../../../../utils/path.js'; import path from 'node:path'; import crypto from 'node:crypto'; import { getAssetsDir } from '../../shared/getAssetsDir.js'; import { assertModuleId, getFilePathToShowToUserModule } from '../../shared/getFilePath.js'; function pluginDistFileNames() { return [ { name: 'vike:build:pluginDistFileNames', apply: 'build', enforce: 'post', configResolved: { handler(config) { const rollupOutputs = getRollupOutputs(config); // We need to support multiple outputs: @vite/plugin-legacy adds an output, see https://github.com/vikejs/vike/issues/477#issuecomment-1406434802 rollupOutputs.forEach((rollupOutput) => { if (!('entryFileNames' in rollupOutput)) { rollupOutput.entryFileNames = (chunkInfo) => getEntryFileName(chunkInfo, config, true); } if (!('chunkFileNames' in rollupOutput)) { rollupOutput.chunkFileNames = (chunkInfo) => getChunkFileName(chunkInfo, config); } if (!('assetFileNames' in rollupOutput)) { rollupOutput.assetFileNames = (chunkInfo) => getAssetFileName(chunkInfo, config); rollupOutput.assetFileNames.isTheOneSetByVike = true; assert(rollupOutput.assetFileNames.isTheOneSetByVike); } else { // If a user needs this: // - assertUsage() that the naming provided by the user ends with `.[hash][extname]` // - It's needed for getHash() of handleAssetsManifest() // - Asset URLs should always contain a hash: it's paramount for caching assets. // - If rollupOutput.assetFileNames is a function then use a wrapper function to apply the assertUsage() assertUsage(rollupOutput.assetFileNames.isTheOneSetByVike, "Setting Vite's configuration build.rollupOptions.output.assetFileNames is currently forbidden. Reach out if you need to use it."); } { const manualChunksOriginal = rollupOutput.manualChunks; rollupOutput.manualChunks = function (id, ...args) { if (manualChunksOriginal) { if (isCallable(manualChunksOriginal)) { const result = manualChunksOriginal.call(this, id, ...args); if (result !== undefined) return result; } else { assertUsage(false, "The Vite's configuration build.rollupOptions.output.manualChunks must be a function. Reach out if you need to set it to another value."); } } // Disable CSS bundling to workaround https://github.com/vikejs/vike/issues/1815 // TO-DO/eventually: let's bundle CSS again once Rolldown replaces Rollup if (id.endsWith('.css')) { const userRootDir = config.root; if (id.startsWith(userRootDir)) { assertPosixPath(id); assertModuleId(id); let name; const isNodeModules = id.match(/node_modules\/([^\/]+)\/(?!.*node_modules)/); if (isNodeModules) { name = isNodeModules[1]; } else { const filePath = getFilePathToShowToUserModule(id, config); name = filePath; name = name.split('.').slice(0, -1).join('.'); // remove file extension name = name.split('/').filter(Boolean).join('_'); } // Make fileHash the same between local development and CI const idStable = path.posix.relative(userRootDir, id); // Don't remove `?` queries because each `id` should belong to a unique bundle. const hash = getIdHash(idStable); return `${name}-${hash}`; } else { let name; const isVirtualModule = id.match(/virtual:([^:]+):/); if (isVirtualModule) { name = isVirtualModule[1]; assert(name); } else if ( // https://github.com/vikejs/vike/issues/1818#issuecomment-2298478321 id.startsWith('/__uno')) { name = 'uno'; } else { name = 'style'; } const hash = getIdHash(id); return `${name}-${hash}`; } } }; } }); }, }, }, ]; } function getIdHash(id) { return crypto.createHash('md5').update(id).digest('hex').slice(0, 8); } function getAssetFileName(assetInfo, config) { const userRootDir = config.root; const assetsDir = getAssetsDir(config); const dir = assetsDir + '/static'; let { name } = assetInfo; if (!name) { return `${dir}/[name].[hash][extname]`; } // https://github.com/vikejs/vike/issues/794 assertPosixPath(name); name = path.posix.basename(name); // dist/client/assets/index.page.server.jsx_extractAssets_lang.e4e33422.css // => dist/client/assets/index.page.server.e4e33422.css if ( // Vite 2 name?.endsWith('_extractAssets_lang.css') || // Vite 3 name?.endsWith('?extractAssets&lang.css')) { name = name.split('.').slice(0, -2).join('.'); name = clean(name, userRootDir); return `${dir}/${name}.[hash][extname]`; } name = name.split('.').slice(0, -1).join('.'); name = clean(name, userRootDir); return `${dir}/${name}.[hash][extname]`; } function getChunkFileName(_chunkInfo, config) { const isForClientSide = !config.build.ssr; let name = 'chunks/chunk-[hash].js'; if (isForClientSide) { const assetsDir = getAssetsDir(config); name = `${assetsDir}/${name}`; } return name; } function getEntryFileName(chunkInfo, config, isEntry) { const userRootDir = config.root; const assetsDir = getAssetsDir(config); const isForClientSide = !config.build.ssr; let { name } = chunkInfo; assertPosixPath(name); name = clean(name, userRootDir, true, // Not needed for client-side because dist/ filenames contain `.[hash].js` !isForClientSide); if (isForClientSide) { return `${assetsDir}/${name}.[hash].js`; } else { return `${name}.${isEntry ? 'mjs' : 'js'}`; } } function removePathSeparators(name) { assertPosixPath(name); assert(!name.startsWith('/'), { name }); const entryDir = 'entries/'; const hasEntryDir = name.startsWith(entryDir); if (hasEntryDir) { name = name.slice(entryDir.length); assert(!name.startsWith('/')); } name = name.split('/').join('_'); if (hasEntryDir) { name = `${entryDir}${name}`; } return name; } function removeUserRootDir(name, userRootDir) { if (name.startsWith(userRootDir)) { name = name.slice(userRootDir.length); if (name.startsWith('/')) name = name.slice(1); } assert(!name.startsWith('/'), { name }); return name; } function clean(name, userRootDir, removePathSep, fixGlob) { name = removeUserRootDir(name, userRootDir); name = fixExtractAssetsQuery(name); if (fixGlob) { name = workaroundGlob(name); } name = replaceNonLatinCharacters(name); if (removePathSep) { name = removePathSeparators(name); } name = removeLeadingUnderscoreInFilename(name); name = removeUnderscoreDoublets(name); // Avoid: // ``` // dist/client/assets/entries/.Dp9wM6PK.js // dist/server/entries/.mjs // ``` assert(!name.endsWith('/')); return name; } function fixExtractAssetsQuery(name) { name = name.replace(/\.[^\.]*_extractAssets_lang$/, '.extractAssets'); return name; } function removeUnderscoreDoublets(name) { name = name.split(/__+/).join('_'); return name; } function replaceNonLatinCharacters(name) { name = name.split('+').join(''); name = name.replace(/[^a-zA-Z0-9\/\._]/g, '-'); return name; } // Remove leading `_` from filename // - GitHub Pages treat URLs with filename starting with `_` differently (removing the need for workaround of creating a .jekyll file) function removeLeadingUnderscoreInFilename(name) { assertPosixPath(name); const paths = name.split('/'); { const last = paths.length - 1; let filename = paths[last]; if (filename.startsWith('_')) { filename = filename.slice(1); paths[last] = filename; name = paths.join('/'); } } return name; } // Ensure import.meta.glob() doesn't match dist/ files function workaroundGlob(name) { // V1 design name = name.split('+').join(''); ['client', 'server', 'route'].forEach((env) => { name = name.split(`.page.${env}`).join(`-page-${env}`); }); name = name.split('.page.').join('-page.'); name = name.replace(/\.page$/, '-page'); return name; } function getRollupOutputs(config) { var _a, _b; // @ts-expect-error is read-only config.build ?? (config.build = {}); (_a = config.build).rollupOptions ?? (_a.rollupOptions = {}); (_b = config.build.rollupOptions).output ?? (_b.output = {}); const { output } = config.build.rollupOptions; if (!isArray(output)) { return [output]; } return output; }