UNPKG

@serwist/turbopack

Version:

A module that integrates Serwist into your Next.js / Turbopack application.

1 lines 13.4 kB
{"version":3,"file":"index.mjs","names":["crypto","fs","path","BuildResult","getFileManifestEntries","rebasePath","SerwistConfigError","validationErrorMap","browserslistToEsbuild","browserslist","cyan","dim","yellow","NextConfig","MODERN_BROWSERSLIST_TARGET","NextResponse","z","injectManifestOptions","logger","LoggingMethods","InjectManifestOptions","InjectManifestOptionsComplete","esbuildWasm","Promise","esbuildNative","logSerwistResult","filePath","buildResult","Pick","count","size","warnings","hasWarnings","length","toFixed","map","w","join","validateGetManifestOptions","input","result","spa","error","success","moduleName","message","prettifyError","data","isDev","process","env","NODE_ENV","contentTypeMap","Record","createSerwistRoute","options","dynamic","const","dynamicParams","revalidate","validation","then","config","disablePrecacheManifest","additionalPrecacheEntries","globIgnores","file","swSrc","baseDirectory","globDirectory","manifestTransforms","manifestEntries","manifest","m","url","startsWith","nextConfig","distDir","assetPrefix","slice","posix","basePath","lastHash","Map","loadMap","injectionPoint","manifestString","undefined","JSON","stringify","log","type","esbuild","useNativeEsbuild","build","sourcemap","format","treeShaking","minify","bundle","esbuildOptions","target","cwd","platform","define","outdir","write","entryNames","assetNames","chunkNames","entryPoints","in","out","errors","console","Error","warn","outputFiles","e","text","generateStaticParams","keys","relative","GET","_","Request","params","rebuildOnChange","swContent","readFileSync","currentHash","createHash","update","digest","get","headers","extname","withSerwist","serverExternalPackages"],"sources":["../src/index.ts"],"sourcesContent":["// Workaround for Next.js + Turbopack, while plugins are still\n// not supported. This relies on Next.js Route Handlers and file\n// name determinism.\nimport crypto from \"node:crypto\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { type BuildResult, getFileManifestEntries, rebasePath } from \"@serwist/build\";\nimport { SerwistConfigError, validationErrorMap } from \"@serwist/build/schema\";\nimport { browserslistToEsbuild } from \"@serwist/utils\";\nimport browserslist from \"browserslist\";\nimport { cyan, dim, yellow } from \"kolorist\";\nimport type { NextConfig } from \"next\";\nimport { MODERN_BROWSERSLIST_TARGET } from \"next/constants.js\";\nimport { NextResponse } from \"next/server.js\";\nimport { z } from \"zod\";\nimport { injectManifestOptions } from \"./index.schema.js\";\nimport { logger } from \"./lib/index.js\";\nimport type { LoggingMethods } from \"./lib/logger.js\";\nimport type { InjectManifestOptions, InjectManifestOptionsComplete } from \"./types.js\";\n\nlet esbuildWasm: Promise<typeof import(\"esbuild-wasm\")> | null = null;\nlet esbuildNative: Promise<typeof import(\"esbuild\")> | null = null;\n\nconst logSerwistResult = (filePath: string, buildResult: Pick<BuildResult, \"count\" | \"size\" | \"warnings\">) => {\n const { count, size, warnings } = buildResult;\n const hasWarnings = warnings && warnings.length > 0;\n // The route is reinitiated for each `path` param, so we only log results\n // if we're prerendering for sw.js.\n if (filePath === \"sw.js\" && (hasWarnings || count > 0)) {\n logger[hasWarnings ? \"warn\" : \"event\"](\n `${cyan(count)} precache entries ${dim(`(${(size / 1024).toFixed(2)} KiB)`)}${\n hasWarnings ? `\\n${yellow([\"⚠ warnings\", ...warnings.map((w) => ` ${w}`), \"\"].join(\"\\n\"))}` : \"\"\n }`,\n );\n }\n};\n\nconst validateGetManifestOptions = async (input: unknown): Promise<InjectManifestOptionsComplete> => {\n const result = await injectManifestOptions.spa(input, {\n error: validationErrorMap,\n });\n if (!result.success) {\n throw new SerwistConfigError({\n moduleName: \"@serwist/turbopack\",\n message: z.prettifyError(result.error),\n });\n }\n return result.data;\n};\n\nconst isDev = process.env.NODE_ENV === \"development\";\n\nconst contentTypeMap: Record<string, string> = {\n \".js\": \"application/javascript\",\n \".map\": \"application/json; charset=UTF-8\",\n};\n\n/**\n * Creates a Route Handler for Serwist files.\n * @param options Options for {@linkcode getFileManifestEntries}.\n */\nexport const createSerwistRoute = (options: InjectManifestOptions) => {\n const dynamic = \"force-static\" as const,\n dynamicParams = false as const,\n revalidate = false as const;\n const validation = validateGetManifestOptions(options).then((config) => {\n return {\n ...config,\n disablePrecacheManifest: isDev,\n additionalPrecacheEntries: isDev ? [] : config.additionalPrecacheEntries,\n globIgnores: [\n ...config.globIgnores,\n // Make sure we leave swSrc out of the precache manifest.\n rebasePath({\n file: config.swSrc,\n baseDirectory: config.globDirectory,\n }),\n ],\n manifestTransforms: [\n ...(config.manifestTransforms ?? []),\n async (manifestEntries) => {\n const manifest = manifestEntries.map((m) => {\n // Replace all references to \"$(distDir)\" with \"$(assetPrefix)/_next/\".\n if (m.url.startsWith(config.nextConfig.distDir)) {\n m.url = `${config.nextConfig.assetPrefix}/_next/${m.url.slice(config.nextConfig.distDir.length)}`;\n }\n // Replace all references to public/ with \"$(basePath)/\".\n if (m.url.startsWith(\"public/\")) {\n m.url = path.posix.join(config.nextConfig.basePath, m.url.slice(7));\n }\n return m;\n });\n return { manifest, warnings: [] };\n },\n ],\n };\n });\n let lastHash: string | null = null;\n let map: Map<string, string> | null = null;\n // NOTE: ALL FILES MUST HAVE DETERMINISTIC NAMES. THIS IS BECAUSE\n // THE FOLLOWING MAP IS LOADED SEPARATELY FOR `generateStaticParams`\n // AND EVERY `GET` REQUEST TO EACH OF THE FILES.\n const loadMap = async (filePath: string) => {\n const config = await validation;\n const { count, size, manifestEntries, warnings } = await getFileManifestEntries(config);\n // See https://github.com/GoogleChrome/workbox/issues/2230\n const injectionPoint = config.injectionPoint || \"\";\n const manifestString = manifestEntries === undefined ? \"undefined\" : JSON.stringify(manifestEntries, null, 2);\n const log = (type: LoggingMethods, ...message: any[]) => {\n if (filePath === \"sw.js\") {\n logger[type](...message);\n }\n };\n let esbuild: typeof import(\"esbuild\");\n if (config.useNativeEsbuild) {\n log(\"info\", \"Using esbuild to bundle the service worker.\");\n if (!esbuildNative) esbuildNative = import(/* webpackIgnore: true */ \"esbuild\");\n esbuild = await esbuildNative;\n } else {\n log(\"info\", \"Using esbuild-wasm to bundle the service worker.\");\n if (!esbuildWasm) esbuildWasm = import(/* webpackIgnore: true */ \"esbuild-wasm\");\n esbuild = await esbuildWasm;\n }\n logSerwistResult(filePath, { count, size, warnings });\n const result = await esbuild.build({\n sourcemap: true,\n format: \"esm\",\n treeShaking: true,\n minify: !isDev,\n bundle: true,\n ...config.esbuildOptions,\n target: config.esbuildOptions?.target ?? browserslistToEsbuild(browserslist, config.cwd, MODERN_BROWSERSLIST_TARGET),\n platform: \"browser\",\n define: {\n ...config.esbuildOptions.define,\n ...(injectionPoint ? { [injectionPoint]: manifestString } : {}),\n },\n outdir: config.cwd,\n write: false,\n entryNames: \"[name]\",\n // Asset and chunk names must be at the top, as our path is `/serwist/[path]`,\n // not `/serwist/[...path]`, meaning that we can't resolve paths deeper\n // than one level.\n assetNames: \"[name]-[hash]\",\n chunkNames: \"[name]-[hash]\",\n entryPoints: [{ in: config.swSrc, out: \"sw\" }],\n });\n if (result.errors.length) {\n console.error(\"Failed to build the service worker.\", result.errors);\n throw new Error();\n }\n if (result.warnings.length) {\n console.warn(result.warnings);\n }\n return new Map(result.outputFiles.map((e) => [e.path, e.text]));\n };\n const generateStaticParams = async () => {\n const config = await validation;\n if (!map) map = await loadMap(\"root\");\n return [...map.keys()].map((e) => ({ path: path.relative(config.cwd, e) }));\n };\n const GET = async (_: Request, { params }: { params: Promise<{ path: string }> }) => {\n const { path: filePath } = await params;\n const config = await validation;\n if (isDev && config.rebuildOnChange) {\n const swContent = fs.readFileSync(config.swSrc, \"utf-8\");\n const currentHash = crypto.createHash(\"sha256\").update(swContent).digest(\"hex\");\n if (!map || lastHash !== currentHash) {\n map = await loadMap(filePath);\n lastHash = currentHash;\n }\n } else if (!map) map = await loadMap(filePath);\n return new NextResponse(map.get(path.join(config.cwd, filePath)), {\n headers: {\n \"Content-Type\": contentTypeMap[path.extname(filePath)] || \"text/plain\",\n \"Service-Worker-Allowed\": \"/\",\n },\n });\n };\n return { dynamic, dynamicParams, revalidate, generateStaticParams, GET };\n};\n\nexport const withSerwist = (nextConfig: NextConfig = {}): NextConfig => ({\n ...nextConfig,\n serverExternalPackages: [...(nextConfig.serverExternalPackages ?? []), \"esbuild\", \"esbuild-wasm\"],\n});\n"],"mappings":"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"}