@serwist/next
Version:
A module that integrates Serwist into your Next.js application.
119 lines (115 loc) • 4.63 kB
JavaScript
import fs from 'node:fs';
import path from 'node:path';
import { rebasePath } from '@serwist/build';
import { browserslistToEsbuild } from '@serwist/utils';
import browserslist from 'browserslist';
import { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD, MODERN_BROWSERSLIST_TARGET } from 'next/constants.js';
import { createRequire } from 'module';
const __require = createRequire(import.meta.url);
const nextConfig = __require("next/dist/server/config.js");
const loadNextConfig = (cwd, isDev)=>{
const nextPhase = isDev ? PHASE_DEVELOPMENT_SERVER : PHASE_PRODUCTION_BUILD;
return nextConfig.default(nextPhase, cwd, {
silent: false
});
};
const generateGlobPatterns = (distDir)=>[
`${distDir}static/**/*.{js,css,html,ico,apng,png,avif,jpg,jpeg,jfif,pjpeg,pjp,gif,svg,webp,json,webmanifest}`,
"public/**/*"
];
const _cwd = process.cwd();
const _isDev = process.env.NODE_ENV === "development";
const serwist = async (options, nextConfig, { cwd = _cwd, isDev = _isDev } = {})=>{
if (!nextConfig) nextConfig = await loadNextConfig(cwd, isDev);
const basePath = nextConfig.basePath || "/";
let distDir = nextConfig.distDir;
if (distDir[0] === "/") distDir = distDir.slice(1);
if (distDir[distDir.length - 1] !== "/") distDir += "/";
const distServerDir = `${distDir}server/`;
const distAppDir = `${distServerDir}app/`;
const distPagesDir = `${distServerDir}pages/`;
const { precachePrerendered = true, globDirectory = cwd, ...cliOptions } = options;
for (const file of [
cliOptions.swDest,
`${cliOptions.swDest}.map`
]){
fs.rmSync(file, {
force: true
});
}
return {
dontCacheBustURLsMatching: new RegExp(`^${distDir}static/`),
disablePrecacheManifest: isDev,
...cliOptions,
globDirectory,
globPatterns: [
...cliOptions.globPatterns ?? generateGlobPatterns(distDir),
...precachePrerendered ? [
`${distServerDir}{app,pages}/**/*.html`
] : []
],
globIgnores: [
`${distAppDir}**/_not-found.html`,
`${distAppDir}_global-error*`,
`${distPagesDir}404.html`,
`${distPagesDir}500.html`,
...cliOptions.globIgnores ?? [],
rebasePath({
baseDirectory: globDirectory,
file: cliOptions.swSrc
}),
rebasePath({
baseDirectory: globDirectory,
file: cliOptions.swDest
}),
rebasePath({
baseDirectory: globDirectory,
file: `${cliOptions.swDest}.map`
})
],
manifestTransforms: [
...cliOptions.manifestTransforms ?? [],
(manifestEntries)=>{
const manifest = manifestEntries.map((m)=>{
if (m.url.startsWith(distAppDir)) {
m.url = m.url.slice(distAppDir.length - 1);
}
if (m.url.startsWith(distPagesDir)) {
m.url = m.url.slice(distPagesDir.length - 1);
}
if (m.url.endsWith(".html")) {
if (m.url.endsWith("/index.html")) {
m.url = m.url.slice(0, m.url.lastIndexOf("/") + 1);
} else {
m.url = m.url.substring(0, m.url.lastIndexOf("."));
}
m.url = path.posix.join(basePath, m.url);
}
if (m.url.startsWith(distDir)) {
m.url = `${nextConfig.assetPrefix ?? ""}/_next/${m.url.slice(distDir.length)}`;
}
if (m.url.startsWith("public/")) {
m.url = path.posix.join(basePath, m.url.slice(7));
}
return m;
});
return {
manifest,
warnings: []
};
}
],
esbuildOptions: {
...cliOptions.esbuildOptions,
target: cliOptions.esbuildOptions?.target ?? browserslistToEsbuild(browserslist, cwd, MODERN_BROWSERSLIST_TARGET)
}
};
};
serwist.withNextConfig = async (optionsFunction, { cwd = _cwd, isDev = _isDev } = {})=>{
const nextConfig = await loadNextConfig(cwd, isDev);
return serwist(await optionsFunction(nextConfig), nextConfig, {
cwd,
isDev
});
};
export { generateGlobPatterns, serwist };