UNPKG

@serwist/build

Version:

A module that integrates into your build process, helping you generate a manifest of local files that should be precached.

475 lines (474 loc) 17.6 kB
import { n as manifestTransformResult, r as manifestEntry } from "./chunks/manifest-transform-BCUeQ0-V.js"; import { z } from "zod"; import { MaybePromise, Require } from "@serwist/utils"; import { RawSourceMap } from "source-map"; import { PackageJson } from "type-fest"; //#region src/types.d.ts type ManifestEntry = z.input<typeof manifestEntry>; type ManifestTransformResult = z.input<typeof manifestTransformResult>; type ManifestTransform = (entries: (ManifestEntry & { size: number; })[], params?: unknown) => MaybePromise<ManifestTransformResult>; type ResolvedManifestTransform = (entries: (ManifestEntry & { size: number; })[], params?: unknown) => Promise<ManifestTransformResult>; interface BasePartial { /** * A list of entries to be precached, in addition to any entries that are * generated as part of the build configuration. */ additionalPrecacheEntries?: (string | ManifestEntry)[]; /** * Whether the precache manifest should be set to `undefined`. Essentially whether `@serwist/build` should * be disabled. Mostly useful when you want it to only check if the provided options are valid. * @default false */ disablePrecacheManifest?: boolean; /** * Assets that match this will be assumed to be uniquely versioned via their * URL, and exempted from the normal HTTP cache-busting that's done when * populating the precache. While not required, it's recommended that if your * existing build process already inserts a `[hash]` value into each filename, * you provide a RegExp that will detect that, as it will reduce the bandwidth * consumed when precaching. */ dontCacheBustURLsMatching?: RegExp; /** * One or more functions which will be applied sequentially against the * generated manifest. If `modifyURLPrefix` or `dontCacheBustURLsMatching` are * also specified, their corresponding transformations will be applied first. */ manifestTransforms?: ManifestTransform[]; /** * Determines the maximum size of files that will be precached. This prevents * you from inadvertently precaching very large files that might have accidentally * matched one of your patterns. * @default 2097152 */ maximumFileSizeToCacheInBytes?: number; /** * An object mapping string prefixes to replacement string values. This can be * used to, e.g., remove or add a path prefix from a manifest entry if your * web hosting setup doesn't match your local filesystem setup. As an * alternative with more flexibility, you can use the `manifestTransforms` * option and provide a function that modifies the entries in the manifest * using whatever logic you provide. * * Example usage: * * ``` * // Replace a '/dist/' prefix with '/', and also prepend * // '/static' to every URL. * modifyURLPrefix: { * '/dist/': '/', * '': '/static', * } * ``` */ modifyURLPrefix?: { [key: string]: string; }; } interface BaseResolved extends Require<BasePartial, "disablePrecacheManifest" | "maximumFileSizeToCacheInBytes"> { manifestTransforms?: ResolvedManifestTransform[]; } interface RequiredGlobDirectoryPartial { /** * The local directory you wish to match `globPatterns` against. The path is * relative to the current directory. */ globDirectory: string; } type RequiredGlobDirectoryResolved = RequiredGlobDirectoryPartial; interface OptionalGlobDirectoryPartial { /** * The local directory you wish to match `globPatterns` against. The path is * relative to the current directory. */ globDirectory?: string; } type OptionalGlobDirectoryResolved = OptionalGlobDirectoryPartial; interface GlobPartial { /** * Determines whether or not symlinks are followed when generating the * precache manifest. For more information, see the definition of `follow` in * [`node-glob`'s documentation](https://github.com/isaacs/node-glob#options). * @default true */ globFollow?: boolean; /** * A set of patterns matching files to always exclude when generating the * precache manifest. For more information, see the definition of `ignore` in * [`node-glob`'s documentation](https://github.com/isaacs/node-glob#options). * @default * ``` * ["**\/node_modules\/**\/*"] * ``` */ globIgnores?: string[]; /** * Files matching any of these patterns will be included in the precache * manifest. For more information, see * [`node-glob`'s Glob Primer](https://github.com/isaacs/node-glob#glob-primer). * @default * ``` * ["**\/*.{js,css,html}"] * ``` */ globPatterns?: string[]; /** * If true, an error reading a directory when generating a precache manifest * will cause the build to fail. If false, the problematic directory will be * skipped. For more information, see the definition of `strict` in * [`node-glob`'s documentation](https://github.com/isaacs/node-glob#options). * @default true */ globStrict?: boolean; /** * If a URL is rendered based on some server-side logic, its contents may * depend on multiple files or on some other unique string value. The keys in * this object are server-rendered URLs. If the values are an array of * strings, they will be interpreted as glob patterns, and the contents of * any files matching the patterns will be used to uniquely version the URL. * If used with a single string, it will be interpreted as unique versioning * information that you've generated for a given URL. */ templatedURLs?: { [key: string]: string | string[]; }; } type GlobResolved = Require<GlobPartial, "globFollow" | "globIgnores" | "globPatterns" | "globStrict">; interface InjectPartial { /** * The string to find inside of the `swSrc` file. Once found, it will be * replaced by the generated precache manifest. * @default "self.__SW_MANIFEST" */ injectionPoint?: string; /** * The path to the service worker file that will be read during * the build process, relative to the current working directory. */ swSrc: string; } type InjectResolved = Require<InjectPartial, "injectionPoint">; interface RequiredSwDestPartial { /** * The path and filename of the service worker file that will be created by * the build process. It must end in '.js'. */ swDest: string; } type RequiredSwDestResolved = RequiredSwDestPartial; interface OptionalSwDestPartial { /** * The path and filename of the service worker file that will be created by * the build process. It must end in '.js'. If omitted, the path will be * based on `swSrc`. */ swDest?: string; } type OptionalSwDestResolved = OptionalSwDestPartial; type GetManifestOptions = BasePartial & GlobPartial & RequiredGlobDirectoryPartial; type GetManifestOptionsComplete = BaseResolved & GlobResolved & RequiredGlobDirectoryResolved; type InjectManifestOptions = BasePartial & GlobPartial & InjectPartial & RequiredSwDestPartial & RequiredGlobDirectoryPartial; type InjectManifestOptionsComplete = BaseResolved & GlobResolved & InjectResolved & RequiredSwDestResolved & RequiredGlobDirectoryResolved; interface GetManifestResult { count: number; manifestEntries: ManifestEntry[] | undefined; size: number; warnings: string[]; } type BuildResult = Omit<GetManifestResult, "manifestEntries"> & { filePaths: string[]; }; /** * @private */ interface FileDetails { file: string; hash: string | null; size: number; } /** * @private */ type BuildType = "dev" | "prod"; /** * @private */ type SerwistPackageJSON = PackageJson; /** * @private */ type MethodNames = "GetManifest" | "InjectManifest" | "WebpackInjectManifest" | "ViteInjectManifest"; //#endregion //#region src/get-manifest.d.ts /** * This method returns a list of URLs to precache, referred to as a "precache * manifest", along with details about the number of entries and their size, * based on the options you provide. * * ``` * // The following lists some common options; see the rest of the documentation * // for the full set of options and defaults. * const {count, manifestEntries, size, warnings} = await getManifest({ * dontCacheBustURLsMatching: [new RegExp('...')], * globDirectory: '...', * globPatterns: ['...', '...'], * maximumFileSizeToCacheInBytes: ..., * }); * ``` */ declare const getManifest: (config: GetManifestOptions) => Promise<GetManifestResult>; //#endregion //#region src/inject-manifest.d.ts /** * This method creates a list of URLs to precache, referred to as a "precache * manifest", based on the options you provide. * * The manifest is injected into the `swSrc` file, and the placeholder string * `injectionPoint` determines where in the file the manifest should go. * * The final service worker file, with the manifest injected, is written to * disk at `swDest`. * * This method will not compile or bundle your `swSrc` file; it just handles * injecting the manifest. * * ``` * // The following lists some common options; see the rest of the documentation * // for the full set of options and defaults. * const {count, size, warnings} = await injectManifest({ * dontCacheBustURLsMatching: [new RegExp('...')], * globDirectory: '...', * globPatterns: ['...', '...'], * maximumFileSizeToCacheInBytes: ..., * swDest: '...', * swSrc: '...', * }); * ``` */ declare const injectManifest: (config: InjectManifestOptions) => Promise<BuildResult>; //#endregion //#region src/lib/constants.d.ts declare const DEFAULT_GLOB_PATTERNS: string[]; //#endregion //#region src/lib/errors.d.ts declare const errors: { "unable-to-get-rootdir": string; "no-extension": string; "invalid-file-manifest-name": string; "unable-to-get-file-manifest-name": string; "invalid-sw-dest": string; "unable-to-get-sw-name": string; "unable-to-get-save-config": string; "unable-to-get-file-hash": string; "unable-to-get-file-size": string; "unable-to-glob-files": string; "unable-to-make-manifest-directory": string; "read-manifest-template-failure": string; "populating-manifest-tmpl-failed": string; "manifest-file-write-failure": string; "unable-to-make-sw-directory": string; "sw-write-failure": string; "sw-write-failure-directory": string; "unable-to-copy-serwist-libraries": string; "invalid-glob-directory": string; "invalid-dont-cache-bust": string; "invalid-exclude-files": string; "invalid-get-manifest-entries-input": string; "invalid-manifest-path": string; "invalid-manifest-entries": string; "invalid-manifest-format": string; "invalid-static-file-globs": string; "invalid-templated-urls": string; "templated-url-matches-glob": string; "invalid-glob-ignores": string; "manifest-entry-bad-url": string; "modify-url-prefix-bad-prefixes": string; "invalid-inject-manifest-arg": string; "injection-point-not-found": string; "multiple-injection-points": string; "bad-template-urls-asset": string; "invalid-generate-file-manifest-arg": string; "invalid-sw-src": string; "same-src-and-dest": string; "no-module-name": string; "bad-manifest-transforms-return-value": string; "string-entry-warning": string; "cant-find-sourcemap": string; "manifest-transforms": string; }; //#endregion //#region src/lib/escape-regexp.d.ts declare const escapeRegExp: (str: string) => string; //#endregion //#region src/lib/get-file-manifest-entries.d.ts declare const getFileManifestEntries: ({ additionalPrecacheEntries, dontCacheBustURLsMatching, globDirectory, globFollow, globIgnores, globPatterns, globStrict, manifestTransforms, maximumFileSizeToCacheInBytes, modifyURLPrefix, templatedURLs, disablePrecacheManifest }: GetManifestOptionsComplete) => Promise<GetManifestResult>; //#endregion //#region src/lib/get-source-map-url.d.ts declare function getSourceMapURL(srcContents: string): string | null; //#endregion //#region src/lib/rebase-path.d.ts declare function rebasePath({ baseDirectory, file }: { baseDirectory: string; file: string; }): string; //#endregion //#region src/lib/replace-and-update-source-map.d.ts interface ReplaceAndUpdateSourceMapOptions { /** * The name for the file whose contents * correspond to originalSource. */ jsFilename: string; /** * The sourcemap for originalSource, * prior to any replacements. */ originalMap: RawSourceMap; /** * The source code, prior to any * replacements. */ originalSource: string; /** * A string to swap in for searchString. */ replaceString: string; /** * A string in originalSource to replace. * Only the first occurrence will be replaced. */ searchString: string; } /** * Adapted from https://github.com/nsams/sourcemap-aware-replace, with modern * JavaScript updates, along with additional properties copied from originalMap. * * @param options * @returns An object containing both * originalSource with the replacement applied, and the modified originalMap. * @private */ declare function replaceAndUpdateSourceMap({ jsFilename, originalMap, originalSource, replaceString, searchString }: ReplaceAndUpdateSourceMapOptions): Promise<{ map: string; source: string; }>; //#endregion //#region src/lib/transform-manifest.d.ts /** * A `ManifestTransform` function can be used to modify the modify the `url` or * `revision` properties of some or all of the {@linkcode ManifestEntry} in the manifest. * * Deleting the `revision` property of an entry will cause * the corresponding `url` to be precached without cache-busting parameters * applied, which is to say, it implies that the URL itself contains * proper versioning info. If the `revision` property is present, it must be * set to a string. * * @example A transformation that prepended the origin of a CDN for any * URL starting with '/assets/' could be implemented as: * * const cdnTransform = async (manifestEntries) => { * const manifest = manifestEntries.map(entry => { * const cdnOrigin = 'https://example.com'; * if (entry.url.startsWith('/assets/')) { * entry.url = cdnOrigin + entry.url; * } * return entry; * }); * return {manifest, warnings: []}; * }; * * @example A transformation that nulls the revision field when the * URL contains an 8-character hash surrounded by '.', indicating that it * already contains revision information: * * const removeRevisionTransform = async (manifestEntries) => { * const manifest = manifestEntries.map(entry => { * const hashRegExp = /\.\w{8}\./; * if (entry.url.match(hashRegExp)) { * entry.revision = null; * } * return entry; * }); * return {manifest, warnings: []}; * }; * * @callback ManifestTransform * @param manifestEntries The full * array of entries, prior to the current transformation. * @param compilation When used in the webpack plugins, this param * will be set to the current `compilation`. * @returns The array of entries with the transformation applied, * and optionally, any warnings that should be reported back to the build tool. */ interface ManifestTransformResultWithWarnings { count: number; size: number; manifestEntries: ManifestEntry[] | undefined; warnings: string[]; } interface TransformManifestOptions extends Pick<BaseResolved, "additionalPrecacheEntries" | "dontCacheBustURLsMatching" | "manifestTransforms" | "maximumFileSizeToCacheInBytes" | "modifyURLPrefix" | "disablePrecacheManifest"> { fileDetails: FileDetails[]; transformParam?: unknown; } declare function transformManifest({ additionalPrecacheEntries, dontCacheBustURLsMatching, fileDetails, manifestTransforms, maximumFileSizeToCacheInBytes, modifyURLPrefix, transformParam, disablePrecacheManifest }: TransformManifestOptions): Promise<ManifestTransformResultWithWarnings>; //#endregion //#region src/lib/translate-url-to-sourcemap-paths.d.ts declare function translateURLToSourcemapPaths(url: string | null, swSrc: string, swDest: string): { destPath: string | undefined; srcPath: string | undefined; warning: string | undefined; }; //#endregion //#region src/lib/validate-options.d.ts declare const validateGetManifestOptions: (input: unknown) => Promise<GetManifestOptionsComplete>; declare const validateInjectManifestOptions: (input: unknown) => Promise<InjectManifestOptionsComplete>; //#endregion //#region src/index.d.ts /** * Use `JSON.stringify` instead. * * @deprecated */ declare const stringify: { (value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string; (value: any, replacer?: (number | string)[] | null, space?: string | number): string; }; //#endregion export { BasePartial, BaseResolved, BuildResult, BuildType, DEFAULT_GLOB_PATTERNS, FileDetails, GetManifestOptions, GetManifestOptionsComplete, GetManifestResult, GlobPartial, GlobResolved, InjectManifestOptions, InjectManifestOptionsComplete, InjectPartial, InjectResolved, ManifestEntry, ManifestTransform, ManifestTransformResult, MethodNames, OptionalGlobDirectoryPartial, OptionalGlobDirectoryResolved, OptionalSwDestPartial, OptionalSwDestResolved, RequiredGlobDirectoryPartial, RequiredGlobDirectoryResolved, RequiredSwDestPartial, RequiredSwDestResolved, ResolvedManifestTransform, SerwistPackageJSON, errors, escapeRegExp, getFileManifestEntries, getManifest, getSourceMapURL, injectManifest, rebasePath, replaceAndUpdateSourceMap, stringify, transformManifest, translateURLToSourcemapPaths, validateGetManifestOptions, validateInjectManifestOptions }; //# sourceMappingURL=index.d.mts.map