@blinkk/root 3.3.1 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-worker.js +2 -2
- package/dist/{chunk-KW7KTYGC.js → chunk-6QWKKJOB.js} +40 -9
- package/dist/chunk-6QWKKJOB.js.map +7 -0
- package/dist/{chunk-M3E4RKS7.js → chunk-DLPHCMFV.js} +43 -5
- package/dist/chunk-DLPHCMFV.js.map +7 -0
- package/dist/{chunk-YU22SAIG.js → chunk-QJ4F45DC.js} +2 -2
- package/dist/{chunk-WGQNQPWG.js → chunk-WRZLI2L2.js} +25 -12
- package/dist/chunk-WRZLI2L2.js.map +7 -0
- package/dist/{chunk-KHO3HMX6.js → chunk-Y4H75NIO.js} +8 -5
- package/dist/chunk-Y4H75NIO.js.map +7 -0
- package/dist/cli.js +4 -4
- package/dist/core/config.d.ts +16 -0
- package/dist/core/core.d.ts +1 -0
- package/dist/core/hooks/useAssetMap.d.ts +22 -0
- package/dist/core.js +7 -1
- package/dist/core.js.map +2 -2
- package/dist/functions/server.d.ts +1 -1
- package/dist/functions.js +4 -4
- package/dist/node.js +2 -2
- package/dist/render/asset-map/asset-map.d.ts +8 -1
- package/dist/render/asset-map/build-asset-map.d.ts +8 -1
- package/dist/render/asset-map/dev-asset-map.d.ts +7 -1
- package/dist/render/render.d.ts +3 -1
- package/dist/render.js +21 -5
- package/dist/render.js.map +2 -2
- package/package.json +30 -31
- package/dist/chunk-KHO3HMX6.js.map +0 -7
- package/dist/chunk-KW7KTYGC.js.map +0 -7
- package/dist/chunk-M3E4RKS7.js.map +0 -7
- package/dist/chunk-WGQNQPWG.js.map +0 -7
- /package/dist/{chunk-YU22SAIG.js.map → chunk-QJ4F45DC.js.map} +0 -0
|
@@ -89,7 +89,10 @@ async function directoryContains(dirpath, subpath) {
|
|
|
89
89
|
|
|
90
90
|
// src/node/monorepo.ts
|
|
91
91
|
import path2 from "node:path";
|
|
92
|
-
import {
|
|
92
|
+
import {
|
|
93
|
+
getWorkspaceInfos,
|
|
94
|
+
getWorkspaceManagerRoot
|
|
95
|
+
} from "workspace-tools";
|
|
93
96
|
function loadPackageJson(filepath) {
|
|
94
97
|
if (!fileExistsSync(filepath)) {
|
|
95
98
|
return null;
|
|
@@ -97,11 +100,11 @@ function loadPackageJson(filepath) {
|
|
|
97
100
|
return loadJsonSync(filepath);
|
|
98
101
|
}
|
|
99
102
|
function getMonorepoPackages(rootDir) {
|
|
100
|
-
const monorepoRoot =
|
|
103
|
+
const monorepoRoot = getWorkspaceManagerRoot(rootDir);
|
|
101
104
|
if (!monorepoRoot) {
|
|
102
105
|
return {};
|
|
103
106
|
}
|
|
104
|
-
const workspaces =
|
|
107
|
+
const workspaces = getWorkspaceInfos(monorepoRoot) || [];
|
|
105
108
|
const packages = {};
|
|
106
109
|
workspaces.forEach((workspaceInfo) => {
|
|
107
110
|
packages[workspaceInfo.name] = workspaceInfo;
|
|
@@ -109,7 +112,7 @@ function getMonorepoPackages(rootDir) {
|
|
|
109
112
|
return packages;
|
|
110
113
|
}
|
|
111
114
|
function getMonorepoPackageDeps(rootDir) {
|
|
112
|
-
const monorepoRoot =
|
|
115
|
+
const monorepoRoot = getWorkspaceManagerRoot(rootDir);
|
|
113
116
|
if (!monorepoRoot) {
|
|
114
117
|
return {};
|
|
115
118
|
}
|
|
@@ -288,4 +291,4 @@ export {
|
|
|
288
291
|
bundleRootConfig,
|
|
289
292
|
loadBundledConfig
|
|
290
293
|
};
|
|
291
|
-
//# sourceMappingURL=chunk-
|
|
294
|
+
//# sourceMappingURL=chunk-Y4H75NIO.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/utils/fsutils.ts", "../src/node/monorepo.ts", "../src/node/load-config.ts"],
|
|
4
|
+
"sourcesContent": ["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport fsExtra from 'fs-extra';\nimport glob from 'tiny-glob';\n\nexport function isJsFile(filename: string) {\n return !!filename.match(/\\.(j|t)sx?$/);\n}\n\nexport async function writeFile(filepath: string, content: string) {\n const dirPath = path.dirname(filepath);\n await makeDir(dirPath);\n await fs.promises.writeFile(filepath, content);\n}\n\nexport async function makeDir(dirpath: string) {\n try {\n await fs.promises.access(dirpath);\n } catch {\n await fs.promises.mkdir(dirpath, {recursive: true});\n }\n}\n\nexport async function copyDir(srcdir: string, dstdir: string) {\n if (!fsExtra.existsSync(srcdir)) {\n return;\n }\n fsExtra.copySync(srcdir, dstdir, {overwrite: true});\n}\n\n/**\n * Copies a glob of files from one directory to another.\n *\n * Example:\n *\n * ```\n * await copyGlob('*.css', 'src/styles', 'dist/html/styles');\n * ```\n */\nexport async function copyGlob(\n pattern: string,\n srcdir: string,\n dstdir: string\n) {\n const files = await glob(pattern, {cwd: srcdir});\n if (files.length > 0) {\n await makeDir(dstdir);\n }\n files.forEach((file) => {\n fsExtra.copySync(path.resolve(srcdir, file), path.resolve(dstdir, file));\n });\n}\n\nexport async function rmDir(dirpath: string) {\n await fs.promises.rm(dirpath, {recursive: true, force: true});\n}\n\nexport async function loadJson<T = unknown>(filepath: string): Promise<T> {\n const content = await fs.promises.readFile(filepath, 'utf-8');\n return JSON.parse(content);\n}\n\nexport function loadJsonSync<T = unknown>(filepath: string): T {\n const content = fs.readFileSync(filepath, 'utf-8');\n return JSON.parse(content);\n}\n\nexport async function writeJson(filepath: string, data: any) {\n const content = JSON.stringify(data, null, 2);\n await writeFile(filepath, content);\n}\n\nexport async function isDirectory(dirpath: string) {\n return fs.promises\n .stat(dirpath)\n .then((fsStat) => {\n return fsStat.isDirectory();\n })\n .catch((err) => {\n if (err.code === 'ENOENT') {\n return false;\n }\n throw err;\n });\n}\n\nexport function fileExists(filepath: string): Promise<boolean> {\n return fs.promises\n .access(filepath)\n .then(() => true)\n .catch(() => false);\n}\n\nexport function fileExistsSync(filepath: string): boolean {\n try {\n fs.accessSync(filepath);\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function dirExists(dirpath: string): Promise<boolean> {\n try {\n const stat = await fs.promises.stat(dirpath);\n return stat.isDirectory();\n } catch (error) {\n if (error.code === 'ENOENT') {\n return false;\n }\n throw error;\n }\n}\n\nexport async function directoryContains(\n dirpath: string,\n subpath: string\n): Promise<boolean> {\n const outer = await fs.promises.realpath(dirpath);\n const inner = await fs.promises.realpath(subpath);\n const rel = path.relative(outer, inner);\n return !rel.startsWith('..');\n}\n\nexport async function listFilesRecursive(dirPath: string): Promise<string[]> {\n const files: string[] = [];\n const entries = await fs.promises.readdir(dirPath, {withFileTypes: true});\n for (const entry of entries) {\n const fullPath = path.join(dirPath, entry.name);\n if (entry.isDirectory()) {\n const subFiles = await listFilesRecursive(fullPath);\n files.push(...subFiles);\n } else {\n files.push(fullPath);\n }\n }\n return files;\n}\n", "import path from 'node:path';\nimport {\n getWorkspaceInfos,\n getWorkspaceManagerRoot,\n PackageInfo,\n} from 'workspace-tools';\nimport {fileExistsSync, loadJsonSync} from '../utils/fsutils.js';\n\ninterface WorkspacePackage {\n name: string;\n path: string;\n packageJson: PackageInfo;\n}\n\nexport function loadPackageJson(filepath: string): PackageInfo | null {\n if (!fileExistsSync(filepath)) {\n return null;\n }\n return loadJsonSync(filepath);\n}\n\n/**\n * Returns a map of all packages in the monorepo and the corresponding\n * package.json path.\n */\nfunction getMonorepoPackages(\n rootDir: string\n): Record<string, WorkspacePackage> {\n const monorepoRoot = getWorkspaceManagerRoot(rootDir);\n if (!monorepoRoot) {\n return {};\n }\n\n const workspaces = getWorkspaceInfos(monorepoRoot) || [];\n const packages: Record<string, WorkspacePackage> = {};\n workspaces.forEach((workspaceInfo) => {\n packages[workspaceInfo.name] = workspaceInfo;\n });\n return packages;\n}\n\n/**\n * Returns the top-level monorepo package's deps, if any.\n */\nexport function getMonorepoPackageDeps(\n rootDir: string\n): Record<string, string> {\n const monorepoRoot = getWorkspaceManagerRoot(rootDir);\n if (!monorepoRoot) {\n return {};\n }\n\n const packageJsonPath = path.join(monorepoRoot, 'package.json');\n const packageJson = loadPackageJson(packageJsonPath);\n return packageJson?.dependencies || {};\n}\n\n/**\n * Flattens package.json deps from the root project dir, taking into account any\n * deps from the monorepo root as well as any `workspace:` deps from within the\n * monorepo.\n */\nexport function flattenPackageDepsFromMonorepo(\n rootDir: string,\n options?: {ignore?: Set<string>}\n): Record<string, string> {\n const packageJsonPath = path.resolve(rootDir, 'package.json');\n const packageJson = loadPackageJson(packageJsonPath);\n const monorepoDeps = getMonorepoPackageDeps(rootDir);\n\n // Flatten `peerDependencies` and `dependencies`.\n const projectDeps = {\n ...packageJson?.peerDependencies,\n ...packageJson?.dependencies,\n };\n\n const allDeps: Record<string, string> = {};\n const workspacePackages = getMonorepoPackages(rootDir);\n const ignore = options?.ignore || new Set();\n Object.entries(projectDeps).forEach(([depName, depVersion]) => {\n if (\n depName.startsWith('@blinkk/root') &&\n depVersion.startsWith('workspace:')\n ) {\n const packageInfo = workspacePackages[depName];\n if (packageInfo) {\n allDeps[depName] = packageInfo.packageJson.version;\n }\n } else if (depVersion.startsWith('workspace:')) {\n // For internal packages within the workspace, recursively collect the\n // deps from those packages.\n if (ignore.has(depName)) {\n return;\n }\n ignore.add(depName);\n const packageInfo = workspacePackages[depName];\n if (packageInfo) {\n const workspacePackageDir = packageInfo.path;\n const deps = flattenPackageDepsFromMonorepo(workspacePackageDir, {\n ignore: ignore,\n });\n for (const key in deps) {\n const currentValue = allDeps[key];\n if (\n deps[key] &&\n deps[key] !== '*' &&\n (!currentValue || currentValue === '*')\n ) {\n allDeps[key] = deps[key];\n }\n }\n }\n } else if (depVersion === '*' && monorepoDeps[depName]) {\n // For any dependencies using a wildcard version `*`, if the top-level\n // package.json has the depdenency defined, overwrite the version.\n allDeps[depName] = monorepoDeps[depName];\n } else {\n allDeps[depName] = depVersion;\n }\n });\n return sortDeps(allDeps);\n}\n\nfunction sortDeps(deps: Record<string, string>): Record<string, string> {\n const keys = Object.keys(deps).sort();\n const sortedDeps: Record<string, string> = {};\n for (const key of keys) {\n sortedDeps[key] = deps[key];\n }\n return sortedDeps;\n}\n", "import path from 'node:path';\nimport {bundleRequire} from 'bundle-require';\nimport {build, Plugin as EsbuildPlugin} from 'esbuild';\nimport {RootConfig} from '../core/config.js';\nimport {fileExists} from '../utils/fsutils.js';\nimport {flattenPackageDepsFromMonorepo} from './monorepo.js';\n\nexport interface ConfigOptions {\n command: string;\n}\n\nexport async function loadRootConfig(\n rootDir: string,\n options: ConfigOptions\n): Promise<RootConfig> {\n const {rootConfig} = await loadRootConfigWithDeps(rootDir, options);\n return rootConfig;\n}\n\nexport async function loadRootConfigWithDeps(\n rootDir: string,\n options: ConfigOptions\n): Promise<{rootConfig: RootConfig; dependencies: string[]}> {\n const configPath = path.resolve(rootDir, 'root.config.ts');\n const exists = await fileExists(configPath);\n if (!exists) {\n throw new Error(`${configPath} does not exist`);\n }\n const configBundle = await bundleRequire({\n filepath: configPath,\n esbuildOptions: {plugins: [esbuildExternalsPlugin({rootDir})]},\n });\n let config = configBundle.mod.default || {};\n if (typeof config === 'function') {\n config = (await config(options)) || {};\n }\n const rootConfig = Object.assign({}, config, {rootDir});\n validateRootconfig(rootConfig);\n return {rootConfig, dependencies: configBundle.dependencies};\n}\n\nfunction validateRootconfig(rootConfig: RootConfig) {\n // Update vite legacy config options.\n const scss: any = rootConfig.vite?.css?.preprocessorOptions?.scss;\n if (scss?.includePaths) {\n console.warn(\n '[deprecation warning] root.config.ts: vite.css.preprocessorOptions.scss.includePaths is deprecated. rename \"includePaths\" -> \"loadPaths\"'\n );\n scss.loadPaths = scss.includePaths;\n }\n}\n\n/**\n * Compiles a root.config.ts file to root.config.js.\n */\nexport async function bundleRootConfig(rootDir: string, outPath: string) {\n const configPath = path.resolve(rootDir, 'root.config.ts');\n const configExists = await fileExists(configPath);\n if (!configExists) {\n throw new Error(`${configPath} does not exist`);\n }\n await build({\n entryPoints: [configPath],\n bundle: true,\n minify: true,\n platform: 'node',\n outfile: outPath,\n sourcemap: 'inline',\n metafile: true,\n format: 'esm',\n plugins: [esbuildExternalsPlugin({rootDir})],\n });\n}\n\n/**\n * Loads a pre-bundled config file from dist/root.config.js.\n */\nexport async function loadBundledConfig(\n rootDir: string,\n options: ConfigOptions\n): Promise<RootConfig> {\n const configPath = path.resolve(rootDir, 'dist/root.config.js');\n const exists = await fileExists(configPath);\n if (!exists) {\n throw new Error(`${configPath} does not exist`);\n }\n const module = await import(configPath);\n let config = module.default || {};\n if (typeof config === 'function') {\n config = (await config(options)) || {};\n }\n return Object.assign({}, config, {rootDir});\n}\n\n/**\n * Externalizes node_modules deps from the package and any dependent packages\n * from the monorepo.\n */\nfunction esbuildExternalsPlugin(options: {rootDir: string}): EsbuildPlugin {\n const rootDir = options.rootDir;\n const allDeps = flattenPackageDepsFromMonorepo(rootDir);\n\n function getPackageName(id: string): string {\n const segments = id.split('/');\n if (segments.length > 1) {\n // Check if package is an org path like `@blinkk/root`.\n if (segments[0].startsWith('@') && segments[0].length > 1) {\n return `${segments[0]}/${segments[1]}`;\n }\n // For imports like `my-package/subpackage`, return `my-package`.\n return segments[0];\n }\n return id;\n }\n\n return {\n name: 'root-externals-plugin',\n setup(build) {\n build.onResolve({filter: /.*/}, (args) => {\n const id = args.path;\n if (id[0] !== '.' && !id.startsWith('@/')) {\n const packageName = getPackageName(id);\n if (packageName in allDeps) {\n return {\n external: true,\n };\n }\n }\n return null;\n });\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["path", "path", "path", "path", "build"]
|
|
7
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
dev,
|
|
9
9
|
preview,
|
|
10
10
|
start
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import "./chunk-
|
|
11
|
+
} from "./chunk-WRZLI2L2.js";
|
|
12
|
+
import "./chunk-QJ4F45DC.js";
|
|
13
13
|
import "./chunk-I3RCAIW7.js";
|
|
14
|
-
import "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
import "./chunk-DLPHCMFV.js";
|
|
15
|
+
import "./chunk-Y4H75NIO.js";
|
|
16
16
|
import "./chunk-3PWR4F2R.js";
|
|
17
17
|
import "./chunk-XSNCF7WU.js";
|
|
18
18
|
import "./chunk-TM6QRBGS.js";
|
package/dist/core/config.d.ts
CHANGED
|
@@ -48,6 +48,22 @@ export interface RootUserConfig {
|
|
|
48
48
|
*/
|
|
49
49
|
entries?: string[];
|
|
50
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Whether to auto-inject `<link rel="modulepreload">` tags for the JS chunks
|
|
53
|
+
* imported by the page's `<script type="module">` tags. Disabled by default;
|
|
54
|
+
* pass `modulePreload: true` to opt in.
|
|
55
|
+
*
|
|
56
|
+
* Root injects a `<script type="module">` tag for every custom element and
|
|
57
|
+
* bundle used on the page, but the shared chunks those scripts import are
|
|
58
|
+
* only discovered once the browser has downloaded and parsed the script.
|
|
59
|
+
* Preloading them removes that request waterfall.
|
|
60
|
+
*
|
|
61
|
+
* Chunks that are already injected as `<script>` tags are skipped, and no
|
|
62
|
+
* tags are injected by the dev server (where modules are served unbundled).
|
|
63
|
+
*
|
|
64
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/modulepreload}
|
|
65
|
+
*/
|
|
66
|
+
modulePreload?: boolean;
|
|
51
67
|
/**
|
|
52
68
|
* Config options for localization and internationalization.
|
|
53
69
|
*/
|
package/dist/core/core.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { Body } from './components/Body.js';
|
|
|
3
3
|
export { Head } from './components/Head.js';
|
|
4
4
|
export { Html, HTML_CONTEXT } from './components/Html.js';
|
|
5
5
|
export { Script } from './components/Script.js';
|
|
6
|
+
export { useAsset, useAssetMap, useAssetUrl } from './hooks/useAssetMap.js';
|
|
6
7
|
export { StringParamsContext, StringParamsProvider, useStringParams, } from './hooks/useStringParams.js';
|
|
7
8
|
export { TranslationMiddlewareProvider, useTranslationMiddleware, } from './hooks/useTranslationsMiddleware.js';
|
|
8
9
|
export { I18nContext, useI18nContext, getTranslations, } from './hooks/useI18nContext.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Asset, AssetMap } from '../../render/asset-map/asset-map.js';
|
|
2
|
+
export declare const ASSET_MAP_CONTEXT: import("preact").Context<AssetMap | null>;
|
|
3
|
+
/**
|
|
4
|
+
* Returns the asset map for the current render.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useAssetMap(): AssetMap;
|
|
7
|
+
/**
|
|
8
|
+
* Returns an asset from the project's module graph. Paths are relative to the
|
|
9
|
+
* project root and may optionally start with `/`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useAsset(src: string): Asset;
|
|
12
|
+
/**
|
|
13
|
+
* Returns the serving URL for a file compiled from the project's module graph.
|
|
14
|
+
*
|
|
15
|
+
* Usage:
|
|
16
|
+
*
|
|
17
|
+
* ```tsx
|
|
18
|
+
* const customJs = useAssetUrl('/bundles/foo.ts');
|
|
19
|
+
* return <div data-custom-js={customJs} />;
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function useAssetUrl(src: string): string;
|
package/dist/core.js
CHANGED
|
@@ -4,9 +4,12 @@ import {
|
|
|
4
4
|
getTranslations,
|
|
5
5
|
replaceParams,
|
|
6
6
|
testPathHasParams,
|
|
7
|
+
useAsset,
|
|
8
|
+
useAssetMap,
|
|
9
|
+
useAssetUrl,
|
|
7
10
|
useI18nContext,
|
|
8
11
|
useRequestContext
|
|
9
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-6QWKKJOB.js";
|
|
10
13
|
import {
|
|
11
14
|
configureServerPlugins,
|
|
12
15
|
getVitePlugins
|
|
@@ -192,6 +195,9 @@ export {
|
|
|
192
195
|
getVitePlugins,
|
|
193
196
|
replaceParams,
|
|
194
197
|
testPathHasParams,
|
|
198
|
+
useAsset,
|
|
199
|
+
useAssetMap,
|
|
200
|
+
useAssetUrl,
|
|
195
201
|
useI18nContext,
|
|
196
202
|
useRequestContext,
|
|
197
203
|
useStringParams,
|
package/dist/core.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/core/config.ts", "../src/core/components/Body.tsx", "../src/core/components/Head.ts", "../src/core/components/Script.ts", "../src/core/hooks/useStringParams.tsx", "../src/core/hooks/useTranslationsMiddleware.tsx", "../src/core/hooks/useTranslations.ts", "../src/core/pod.ts"],
|
|
4
|
-
"sourcesContent": ["import {UserConfig as ViteUserConfig} from 'vite';\nimport {JsxRenderOptions} from '../jsx/jsx-render.js';\nimport {HtmlMinifyOptions} from '../render/html-minify.js';\nimport {HtmlPrettyOptions} from '../render/html-pretty.js';\nimport {Plugin} from './plugin.js';\nimport {PodConfig} from './pod.js';\nimport {RequestMiddleware} from './types.js';\n\nexport interface RootUserConfig {\n /**\n * Canonical domain the website will serve on. Useful for things like the\n * sitemap, SEO tags, etc.\n */\n domain?: string;\n\n /**\n * The base URL path that the site will serve on. Defaults to `/`;\n */\n base?: string;\n\n /**\n * Config for auto-injecting custom element dependencies.\n */\n elements?: {\n /**\n * A list of directories to use to look for custom elements. The dir path\n * should be relative to the project dir, e.g. \"path/to/elements\".\n */\n include?: string[];\n\n /**\n * A list of RegEx patterns to exclude. The string passed to the RegEx is\n * the file URL relative to the project root, e.g. \"/elements/foo/foo.ts\".\n */\n exclude?: RegExp[];\n };\n\n /**\n * Config for manually injecting stylesheet entries as\n * `<link rel=\"stylesheet\">` tags.\n */\n styles?: {\n /**\n * Project-root-relative stylesheet files to include on every rendered\n * page, e.g. `styles/index.css`.\n *\n * Entries are normalized as URL paths, so both `styles/index.css` and\n * `/styles/index.css` resolve to `/styles/index.css`.\n *\n * Manual entries are injected first, then auto-collected CSS\n * dependencies are merged after. Duplicate URLs are de-duped so each\n * stylesheet is only injected once.\n */\n entries?: string[];\n };\n\n /**\n * Config options for localization and internationalization.\n */\n i18n?: RootI18nConfig;\n\n /**\n * Config options for the Root.js express server.\n */\n server?: RootServerConfig;\n\n /**\n * Build options for the `root build` command.\n */\n build?: RootBuildConfig;\n\n /**\n * Vite config.\n * @see {@link https://vitejs.dev/config/} for more information.\n */\n vite?: ViteUserConfig;\n\n /**\n * Config for the built-in JSX-to-HTML renderer.\n *\n * - `mode: 'pretty'` (default) \u2014 block-level elements render on their own\n * line with no indentation.\n * - `mode: 'minimal'` \u2014 compact output with no extra whitespace.\n *\n * Use `blockElements` to specify additional custom element tag names that\n * should be treated as block-level in pretty mode.\n *\n * @example\n * ```ts\n * export default defineConfig({\n * jsxRenderer: {\n * mode: 'pretty',\n * blockElements: ['my-card', 'my-section'],\n * },\n * });\n * ```\n */\n jsxRenderer?: JsxRenderOptions;\n\n /**\n * Whether to minify HTML output via html-minifier-terser. Disabled by\n * default; pass `minifyHtml: true` to opt in.\n *\n * Ignored when the built-in JSX renderer (`jsxRenderer`) is enabled, since\n * that renderer controls its own output formatting via its `mode` option.\n */\n minifyHtml?: boolean;\n\n /**\n * Options to pass to html-minifier-terser.\n */\n minifyHtmlOptions?: HtmlMinifyOptions;\n\n /**\n * Whether to pretty print HTML output via js-beautify. Disabled by default;\n * pass `prettyHtml: true` to opt in. When both `prettyHtml` and `minifyHtml`\n * are set, `prettyHtml` takes precedence.\n *\n * Ignored when the built-in JSX renderer (`jsxRenderer`) is enabled, since\n * that renderer controls its own output formatting via its `mode` option.\n */\n prettyHtml?: boolean;\n\n /**\n * Options to pass to js-beautify.\n */\n prettyHtmlOptions?: HtmlPrettyOptions;\n\n /**\n * Whether to include a sitemap.xml file to the build output.\n */\n sitemap?: boolean;\n\n /**\n * Plugins.\n */\n plugins?: Plugin[];\n\n /**\n * Per-pod user-level overrides. The key is the pod name as declared in\n * Pod.name.\n */\n pods?: Record<string, PodConfig>;\n\n /**\n * Experimental config options. Note: these are subject to change at any time.\n */\n experiments?: {\n /** Whether to render `<script>` tags with `async`. */\n enableScriptAsync?: boolean;\n };\n}\n\nexport type RootConfig = RootUserConfig & {\n rootDir: string;\n};\n\nexport interface LocaleGroup {\n label?: string;\n locales: RootLocale[];\n}\n\n/**\n * A site-defined locale identifier, as configured in `i18n.locales`.\n * Root is agnostic to its format.\n */\nexport type RootLocale = string;\n\n/**\n * The language identifier used by translation systems (CSV/Sheets columns,\n * translation services, CMS translations pages), mapped from a root locale\n * via `i18n.translationLanguages`. Defaults to the root locale id.\n */\nexport type TranslationLanguage = string;\n\nexport interface RootI18nConfig {\n /**\n * Locales enabled for the site.\n */\n locales?: RootLocale[];\n\n /**\n * The default locale to use. Defaults is `en`.\n */\n defaultLocale?: RootLocale;\n\n /**\n * URL format for localized content. Default is `/[locale]/[base]/[path]`.\n */\n urlFormat?: string;\n\n /**\n * Localization groups, to help UIs (like Root.js CMS) logically group\n * locales.\n */\n groups?: Record<string, LocaleGroup>;\n\n /**\n * Maps a root locale to the \"translation language\" used by translation\n * systems. Translation systems often use different language identifiers\n * than root locales, and multiple root locales may share the same\n * translations. For example:\n *\n * ```\n * i18n: {\n * locales: ['en', 'es_mx', 'es_co', 'en_gb', 'en_ca', 'fr_ca'],\n * translationLanguages: {\n * es_mx: 'es-419',\n * es_co: 'es-419',\n * en_gb: 'en-GB',\n * en_ca: 'en-GB',\n * fr_ca: 'fr-CA',\n * },\n * }\n * ```\n *\n * With the config above, translations for the `es_mx` and `es_co` locales\n * are imported and exported using a single `es-419` language. The\n * conversion applies anywhere translations are used, e.g. CSV and Google\n * Sheets import/export, translation services, and the CMS translations\n * pages. Locales not listed here use the locale id as the translation\n * language.\n */\n translationLanguages?: Record<RootLocale, TranslationLanguage>;\n\n /**\n * Locale fallback chains for translations. When a translation is missing\n * for a locale, each fallback locale is checked (in order) before falling\n * back to `defaultLocale` and finally the source string. Fallbacks are\n * resolved recursively, e.g. with the config below, `en-CA` resolves to\n * `['en-CA', 'en-GB', 'en']`. For example:\n *\n * ```\n * i18n: {\n * locales: ['en', 'en-GB', 'en-CA'],\n * fallbacks: {\n * 'en-CA': ['en-GB'],\n * },\n * }\n * ```\n */\n fallbacks?: Record<RootLocale, RootLocale[]>;\n}\n\nexport interface RootBuildConfig {\n /**\n * Excludes the `/intl/{defaultLocale}/...` path from the SSG build.\n */\n excludeDefaultLocaleFromIntlPaths?: boolean;\n}\n\nexport interface RootRedirectConfig {\n /**\n * The source path to redirect. Accepts placeholders in the format\n * `[key]` or `[...key]`. Use `[key]` for single segments and\n * `[...key]` for multi-segment wildcards.\n * @example \"/old-path/[id]\" or \"/old-path/[...wildcard]\"\n */\n source: string;\n\n /**\n * The destination to redirect to. Placeholders from the source can\n * optionally be inserted into the destination using the same\n * placeholder format.\n * @example \"/new-path/[id]\" or \"/new-path/[...wildcard]\"\n */\n destination: string;\n\n /**\n * The redirect type (`301` = permanent, `302` = temporary). If unspecified,\n * defaults to `302` (temporary).\n */\n type?: 301 | 302;\n}\n\nexport interface RootHeaderConfig {\n /** A glob pattern match (regex not supported yet). */\n source: string;\n headers: Array<{\n key: string;\n value: string;\n }>;\n}\n\nexport interface ContentSecurityPolicyConfig {\n directives?: Record<string, string[]>;\n reportOnly?: boolean;\n}\n\nexport interface XFrameOptionsConfig {\n action: 'DENY' | 'SAMEORIGIN';\n}\n\nexport interface RootSecurityConfig {\n /**\n * Content-Security-Policy config. If enabled, a nonce is auto-generated\n * for every request and appended to script and stylesheet tags. You can\n * validate your CSP headers using a tool like {@link https://csp-evaluator.withgoogle.com/}.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP}\n */\n contentSecurityPolicy?: ContentSecurityPolicyConfig | boolean;\n\n /**\n * Strict-Transport-Security config. When enabled, the header value is set\n * to `Strict-Transport-Security: max-age=63072000; includeSubDomains; preload`.\n */\n strictTransportSecurity?: boolean;\n\n /**\n * X-Content-Type-Options config. When enabled, the header value is set to\n * `X-Content-Type-Options: nosniff`.\n */\n xContentTypeOptions?: boolean;\n\n /**\n * X-Frame-Options config. Setting this value to `true` will default the\n * header value to `X-Frame-Options: SAMEORIGIN`.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options}\n */\n xFrameOptions?: 'DENY' | 'SAMEORIGIN' | boolean;\n\n /**\n * X-XSS-Protection config. When enabled, the header value is set to\n * `X-XSS-Protection: 1; mode=block`.\n */\n xXssProtection?: boolean;\n}\n\nexport interface RootServerConfig {\n /**\n * An array of middleware to add to the express server. These middleware are\n * added to the beginning of the express app.\n */\n middlewares?: RequestMiddleware[];\n\n /**\n * The `trailingSlash` config allows you to control how the server handles\n * trailing slashes. This config only affects URLs that do not have a file\n * extension (i.e. HTML paths).\n *\n * - When `true`, the server redirects URLs to add a trailing slash\n * - When `false`, the server redirects URLs to remove a trailing slash\n * - When unspecified, the server allows URLs with and without trailing slash\n */\n trailingSlash?: boolean;\n\n /**\n * Cookie secret for the session middleware.\n *\n * Generate a secure secret with:\n * ```\n * node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"\n * ```\n */\n sessionCookieSecret?: string | string[];\n\n /**\n * List of redirects. Supports optional wildcards.\n *\n * @example\n * ```ts\n * redirects: [\n * {\n * source: '/old-path/[id]',\n * destination: '/new-path/[id]',\n * type: 301,\n * },\n * {\n * source: '/old-path/[...wildcard]',\n * destination: '/new-path/[...wildcard]',\n * },\n * ]\n * ```\n */\n redirects?: RootRedirectConfig[];\n\n /**\n * HTTP headers to add to a response.\n */\n headers?: RootHeaderConfig[];\n\n /**\n * HTTP security settings. By default, all security settings are enabled with\n * commonly used default values.\n */\n security?: RootSecurityConfig;\n\n /**\n * Home page URL path, which is printed when the dev server starts.\n */\n homePagePath?: string;\n}\n\nexport function defineConfig(config: RootUserConfig): RootUserConfig {\n return config;\n}\n", "import {ComponentChildren, FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type BodyProps = preact.JSX.HTMLAttributes<HTMLBodyElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The `<Body>` component can be used to update attrs in the `<body>` tag.\n *\n * Usage:\n *\n * ```tsx\n * <Body className=\"body\">\n * <h1>Hello world</h1>\n * </Body>\n * ```\n *\n * Output:\n *\n * ```html\n * <body class=\"body\">\n * <h1>Hello world</h1>\n * </body>\n */\nexport const Body: FunctionalComponent<BodyProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Body> component'\n );\n }\n context.bodyAttrs = attrs;\n return <>{children}</>;\n};\n", "import {ComponentChildren, FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type HeadProps = preact.JSX.HTMLAttributes<HTMLHeadElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The <Head> component can be used for injecting elements into the HTML head\n * tag from any part of a page. The <Head> can be added via any component or\n * sub-component and will automatically be hoisted to the `<head>` element.\n *\n * Usage:\n *\n * ```tsx\n * <Head>\n * <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n * </Head>\n * ```\n */\nexport const Head: FunctionalComponent<HeadProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Head> component'\n );\n }\n context.headComponents.push(children);\n context.headAttrs = attrs;\n return null;\n};\n", "import {FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type ScriptProps = preact.JSX.HTMLAttributes<HTMLScriptElement> & {\n // Cast the \"src\" attr to string. See:\n // https://github.com/blinkk/rootjs/issues/519\n src?: string;\n};\n\n/**\n * The <Script> component is used for rendering any custom script modules. At\n * the moment, the system only pre-renders and bundles files that are in the\n * `/bundles` folder at the root of the project.\n *\n * Usage:\n *\n * ```tsx\n * <Script src=\"/bundles/main.ts\" />\n * ```\n */\nexport const Script: FunctionalComponent<ScriptProps> = (props) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Script> component'\n );\n }\n context.scriptDeps.push(props);\n return null;\n};\n", "import {ComponentChildren, FunctionalComponent, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport type StringParamsContext = Record<string, string>;\n\nexport const STRING_PARAMS_CONTEXT = createContext<StringParamsContext | null>(\n null\n);\n\nexport interface StringParamsProviderProps {\n value?: StringParamsContext;\n children?: ComponentChildren;\n}\n\nexport const StringParamsProvider: FunctionalComponent<\n StringParamsProviderProps\n> = (props) => {\n // Allow for nested param values from parent content providers.\n const parent = useContext(STRING_PARAMS_CONTEXT) || {};\n const merged = {...parent, ...props.value};\n return (\n <STRING_PARAMS_CONTEXT.Provider value={merged}>\n {props.children}\n </STRING_PARAMS_CONTEXT.Provider>\n );\n};\n\n/**\n * A hook that returns a map of string params, configured via the\n * `StringParamsProvider` context provider. These params are automatically\n * applied to the `useTranslations()` hook.\n *\n *\n * Usage:\n *\n * ```\n * export default function Page() {\n * return (\n * <StringParamsProvider value={{name: 'Alice'}}>\n * <SayHello />\n * </StringParamsProvider>\n * );\n * }\n *\n * function SayHello() {\n * const t = useTranslations();\n * return <h1>{t('Hello, {name}!')}</h1>;\n * }\n * ```\n *\n * This should render `<h1>Hello, Alice!</h1>`.\n */\nexport function useStringParams() {\n return useContext(STRING_PARAMS_CONTEXT) || {};\n}\n", "import {ComponentChildren, FunctionalComponent, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\ntype TransformFn = (str: string) => string;\n\nexport interface TranslationMiddleware {\n /** Transform the string before translation lookup. */\n beforeTranslate?: TransformFn;\n /** Transform the string after translation lookup. */\n afterTranslate?: TransformFn;\n /** Transform the string before `{param}` values are replaced. */\n beforeReplaceParams?: TransformFn;\n /** Transform the string after `{param}` values are replaced. */\n afterReplaceParams?: TransformFn;\n}\n\nexport interface TranslationMiddlewareContext {\n beforeTranslateFns: TransformFn[];\n afterTranslateFns: TransformFn[];\n beforeReplaceParamsFns: TransformFn[];\n afterReplaceParamsFns: TransformFn[];\n}\n\nconst TRANSLATION_MIDDLEWARE_CONTEXT =\n createContext<TranslationMiddlewareContext | null>(null);\n\nexport interface TranslationMiddlewareProviderProps {\n value?: TranslationMiddleware;\n children?: ComponentChildren;\n}\n\nexport const TranslationMiddlewareProvider: FunctionalComponent<\n TranslationMiddlewareProviderProps\n> = (props) => {\n const parent = useContext(TRANSLATION_MIDDLEWARE_CONTEXT) || {\n beforeTranslateFns: [],\n afterTranslateFns: [],\n beforeReplaceParamsFns: [],\n afterReplaceParamsFns: [],\n };\n const merged: TranslationMiddlewareContext = {\n beforeTranslateFns: [...parent.beforeTranslateFns],\n afterTranslateFns: [...parent.afterTranslateFns],\n beforeReplaceParamsFns: [...parent.beforeReplaceParamsFns],\n afterReplaceParamsFns: [...parent.afterReplaceParamsFns],\n };\n if (props.value?.beforeTranslate) {\n merged.beforeTranslateFns.push(props.value.beforeTranslate);\n }\n if (props.value?.afterTranslate) {\n merged.afterTranslateFns.push(props.value.afterTranslate);\n }\n if (props.value?.beforeReplaceParams) {\n merged.beforeReplaceParamsFns.push(props.value.beforeReplaceParams);\n }\n if (props.value?.afterReplaceParams) {\n merged.afterReplaceParamsFns.push(props.value.afterReplaceParams);\n }\n return (\n <TRANSLATION_MIDDLEWARE_CONTEXT.Provider value={merged}>\n {props.children}\n </TRANSLATION_MIDDLEWARE_CONTEXT.Provider>\n );\n};\n\nexport function useTranslationMiddleware(): TranslationMiddlewareContext {\n return (\n useContext(TRANSLATION_MIDDLEWARE_CONTEXT) || {\n beforeTranslateFns: [],\n afterTranslateFns: [],\n beforeReplaceParamsFns: [],\n afterReplaceParamsFns: [],\n }\n );\n}\n", "import {I18nContext, useI18nContext} from './useI18nContext.js';\nimport {useStringParams} from './useStringParams.js';\nimport {useTranslationMiddleware} from './useTranslationsMiddleware.js';\n\n/**\n * A hook that returns a function that can be used to translate a string, and\n * optionally replace any parameterized values that are surrounded in curly\n * braces.\n *\n * Usage:\n *\n * ```ts\n * const t = useTranslations();\n * t('Hello {name}', {name: 'Bob'});\n * // => 'Bounjour Bob'\n * ```\n */\nexport function useTranslations() {\n // Ignore I18nContext not found error when used with client-side rehydration.\n let i18nContext: I18nContext | null = null;\n try {\n i18nContext = useI18nContext();\n } catch {\n console.warn('I18nContext not found');\n }\n const translations = i18nContext?.translations || {};\n const stringParams = useStringParams();\n const middleware = useTranslationMiddleware();\n\n function t(str: string, params?: Record<string, string | number>): string;\n function t(\n str: string | null | undefined,\n params?: Record<string, string | number>\n ): string | undefined {\n // Suppress verbatim `'undefined'` and `'null'` output, which can occur when\n // using `useTranslations` with undefined values.\n if (typeof str === 'undefined' || str === null) {\n // Return `undefined` to suppress empty props, e.g.\n // <a title={t(undefined)}>Learn more</a>\n return undefined;\n }\n let input = normalizeString(str);\n middleware.beforeTranslateFns.forEach((fn) => {\n input = fn(input);\n });\n let translation = translations[input] ?? input ?? '';\n middleware.afterTranslateFns.forEach((fn) => {\n translation = fn(translation);\n });\n\n // Replace string params, e.g. \"Hello, {name}\".\n middleware.beforeReplaceParamsFns.forEach((fn) => {\n translation = fn(translation);\n });\n if (testHasStringParams(translation)) {\n translation = replaceStringParams(translation, {\n ...stringParams,\n ...params,\n });\n }\n middleware.afterReplaceParamsFns.forEach((fn) => {\n translation = fn(translation);\n });\n\n return translation;\n }\n return t;\n}\n\n/**\n * Cleans a string that's used for translations. Performs the following:\n * - Removes any leading/trailing whitespace\n * - Removes spaces at the end of any line\n */\nexport function normalizeString(str: string) {\n const lines = String(str)\n .trim()\n .split('\\n')\n .map((line) => removeTrailingWhitespace(line));\n return lines.join('\\n');\n}\n\nfunction removeTrailingWhitespace(str: string) {\n return String(str)\n .trimEnd()\n .replace(/ $/, '');\n}\n\nfunction testHasStringParams(str: string) {\n return str.includes('{') && str.includes('}');\n}\n\n/**\n * Replaces string placeholder params, e.g.\n *\n * ```\n * replaceStringParams('Hello, {name}!', {name: 'Joe'})\n * // => 'Hello, Joe!'\n * ```\n */\nfunction replaceStringParams(\n str: string,\n params: Record<string, string | number>\n): string {\n return str.replace(/{([^}]+)}/g, (match, key) => {\n if (key in params) {\n return String(params[key]);\n }\n return match;\n });\n}\n", "import {PluginOption as VitePlugin} from 'vite';\nimport {RootConfig} from './config.js';\n\nexport interface Pod {\n /** Unique pod name, e.g. '@blinkk/root-docs-pod'. */\n name: string;\n\n /**\n * URL prefix for pod routes. Routes within the pod are served under this\n * mount path. Defaults to '/'.\n */\n mount?: string;\n\n /**\n * Priority for route conflict resolution. Higher values win when multiple\n * pods register the same URL path. User-site routes always take precedence\n * regardless of priority. Defaults to 0.\n */\n priority?: number;\n\n /** Absolute path to the pod's routes/ directory. */\n routesDir?: string;\n\n /** Absolute path(s) to the pod's elements/ directory(s). */\n elementsDirs?: string[];\n\n /** Absolute path to the pod's bundles/ directory. */\n bundlesDir?: string;\n\n /** Absolute path to the pod's collections/ directory (root-cms only). */\n collectionsDir?: string;\n\n /** Absolute path to the pod's translations/ directory. */\n translationsDir?: string;\n\n /** Extra Vite plugins contributed by the pod. */\n vitePlugins?: VitePlugin[];\n}\n\nexport type PodFactory = (ctx: {rootConfig: RootConfig}) => Pod | Promise<Pod>;\n\nexport interface PodConfig {\n /** Whether the pod is enabled. Defaults to true. */\n enabled?: boolean;\n\n /** Override the pod's mount path. */\n mount?: string;\n\n /** Override the pod's priority. */\n priority?: number;\n\n /** Filter pod routes. */\n routes?: {\n exclude?: (string | RegExp)[];\n };\n\n /** Configure pod collections. */\n collections?: {\n exclude?: string[];\n /** Rename collection ids, e.g. {Posts: 'DocsPosts'}. */\n rename?: Record<string, string>;\n };\n}\n\n/**\n * Helper to define a pod with type-checking.\n */\nexport function definePod(pod: Pod): Pod {\n return pod;\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import {UserConfig as ViteUserConfig} from 'vite';\nimport {JsxRenderOptions} from '../jsx/jsx-render.js';\nimport {HtmlMinifyOptions} from '../render/html-minify.js';\nimport {HtmlPrettyOptions} from '../render/html-pretty.js';\nimport {Plugin} from './plugin.js';\nimport {PodConfig} from './pod.js';\nimport {RequestMiddleware} from './types.js';\n\nexport interface RootUserConfig {\n /**\n * Canonical domain the website will serve on. Useful for things like the\n * sitemap, SEO tags, etc.\n */\n domain?: string;\n\n /**\n * The base URL path that the site will serve on. Defaults to `/`;\n */\n base?: string;\n\n /**\n * Config for auto-injecting custom element dependencies.\n */\n elements?: {\n /**\n * A list of directories to use to look for custom elements. The dir path\n * should be relative to the project dir, e.g. \"path/to/elements\".\n */\n include?: string[];\n\n /**\n * A list of RegEx patterns to exclude. The string passed to the RegEx is\n * the file URL relative to the project root, e.g. \"/elements/foo/foo.ts\".\n */\n exclude?: RegExp[];\n };\n\n /**\n * Config for manually injecting stylesheet entries as\n * `<link rel=\"stylesheet\">` tags.\n */\n styles?: {\n /**\n * Project-root-relative stylesheet files to include on every rendered\n * page, e.g. `styles/index.css`.\n *\n * Entries are normalized as URL paths, so both `styles/index.css` and\n * `/styles/index.css` resolve to `/styles/index.css`.\n *\n * Manual entries are injected first, then auto-collected CSS\n * dependencies are merged after. Duplicate URLs are de-duped so each\n * stylesheet is only injected once.\n */\n entries?: string[];\n };\n\n /**\n * Whether to auto-inject `<link rel=\"modulepreload\">` tags for the JS chunks\n * imported by the page's `<script type=\"module\">` tags. Disabled by default;\n * pass `modulePreload: true` to opt in.\n *\n * Root injects a `<script type=\"module\">` tag for every custom element and\n * bundle used on the page, but the shared chunks those scripts import are\n * only discovered once the browser has downloaded and parsed the script.\n * Preloading them removes that request waterfall.\n *\n * Chunks that are already injected as `<script>` tags are skipped, and no\n * tags are injected by the dev server (where modules are served unbundled).\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/modulepreload}\n */\n modulePreload?: boolean;\n\n /**\n * Config options for localization and internationalization.\n */\n i18n?: RootI18nConfig;\n\n /**\n * Config options for the Root.js express server.\n */\n server?: RootServerConfig;\n\n /**\n * Build options for the `root build` command.\n */\n build?: RootBuildConfig;\n\n /**\n * Vite config.\n * @see {@link https://vitejs.dev/config/} for more information.\n */\n vite?: ViteUserConfig;\n\n /**\n * Config for the built-in JSX-to-HTML renderer.\n *\n * - `mode: 'pretty'` (default) \u2014 block-level elements render on their own\n * line with no indentation.\n * - `mode: 'minimal'` \u2014 compact output with no extra whitespace.\n *\n * Use `blockElements` to specify additional custom element tag names that\n * should be treated as block-level in pretty mode.\n *\n * @example\n * ```ts\n * export default defineConfig({\n * jsxRenderer: {\n * mode: 'pretty',\n * blockElements: ['my-card', 'my-section'],\n * },\n * });\n * ```\n */\n jsxRenderer?: JsxRenderOptions;\n\n /**\n * Whether to minify HTML output via html-minifier-terser. Disabled by\n * default; pass `minifyHtml: true` to opt in.\n *\n * Ignored when the built-in JSX renderer (`jsxRenderer`) is enabled, since\n * that renderer controls its own output formatting via its `mode` option.\n */\n minifyHtml?: boolean;\n\n /**\n * Options to pass to html-minifier-terser.\n */\n minifyHtmlOptions?: HtmlMinifyOptions;\n\n /**\n * Whether to pretty print HTML output via js-beautify. Disabled by default;\n * pass `prettyHtml: true` to opt in. When both `prettyHtml` and `minifyHtml`\n * are set, `prettyHtml` takes precedence.\n *\n * Ignored when the built-in JSX renderer (`jsxRenderer`) is enabled, since\n * that renderer controls its own output formatting via its `mode` option.\n */\n prettyHtml?: boolean;\n\n /**\n * Options to pass to js-beautify.\n */\n prettyHtmlOptions?: HtmlPrettyOptions;\n\n /**\n * Whether to include a sitemap.xml file to the build output.\n */\n sitemap?: boolean;\n\n /**\n * Plugins.\n */\n plugins?: Plugin[];\n\n /**\n * Per-pod user-level overrides. The key is the pod name as declared in\n * Pod.name.\n */\n pods?: Record<string, PodConfig>;\n\n /**\n * Experimental config options. Note: these are subject to change at any time.\n */\n experiments?: {\n /** Whether to render `<script>` tags with `async`. */\n enableScriptAsync?: boolean;\n };\n}\n\nexport type RootConfig = RootUserConfig & {\n rootDir: string;\n};\n\nexport interface LocaleGroup {\n label?: string;\n locales: RootLocale[];\n}\n\n/**\n * A site-defined locale identifier, as configured in `i18n.locales`.\n * Root is agnostic to its format.\n */\nexport type RootLocale = string;\n\n/**\n * The language identifier used by translation systems (CSV/Sheets columns,\n * translation services, CMS translations pages), mapped from a root locale\n * via `i18n.translationLanguages`. Defaults to the root locale id.\n */\nexport type TranslationLanguage = string;\n\nexport interface RootI18nConfig {\n /**\n * Locales enabled for the site.\n */\n locales?: RootLocale[];\n\n /**\n * The default locale to use. Defaults is `en`.\n */\n defaultLocale?: RootLocale;\n\n /**\n * URL format for localized content. Default is `/[locale]/[base]/[path]`.\n */\n urlFormat?: string;\n\n /**\n * Localization groups, to help UIs (like Root.js CMS) logically group\n * locales.\n */\n groups?: Record<string, LocaleGroup>;\n\n /**\n * Maps a root locale to the \"translation language\" used by translation\n * systems. Translation systems often use different language identifiers\n * than root locales, and multiple root locales may share the same\n * translations. For example:\n *\n * ```\n * i18n: {\n * locales: ['en', 'es_mx', 'es_co', 'en_gb', 'en_ca', 'fr_ca'],\n * translationLanguages: {\n * es_mx: 'es-419',\n * es_co: 'es-419',\n * en_gb: 'en-GB',\n * en_ca: 'en-GB',\n * fr_ca: 'fr-CA',\n * },\n * }\n * ```\n *\n * With the config above, translations for the `es_mx` and `es_co` locales\n * are imported and exported using a single `es-419` language. The\n * conversion applies anywhere translations are used, e.g. CSV and Google\n * Sheets import/export, translation services, and the CMS translations\n * pages. Locales not listed here use the locale id as the translation\n * language.\n */\n translationLanguages?: Record<RootLocale, TranslationLanguage>;\n\n /**\n * Locale fallback chains for translations. When a translation is missing\n * for a locale, each fallback locale is checked (in order) before falling\n * back to `defaultLocale` and finally the source string. Fallbacks are\n * resolved recursively, e.g. with the config below, `en-CA` resolves to\n * `['en-CA', 'en-GB', 'en']`. For example:\n *\n * ```\n * i18n: {\n * locales: ['en', 'en-GB', 'en-CA'],\n * fallbacks: {\n * 'en-CA': ['en-GB'],\n * },\n * }\n * ```\n */\n fallbacks?: Record<RootLocale, RootLocale[]>;\n}\n\nexport interface RootBuildConfig {\n /**\n * Excludes the `/intl/{defaultLocale}/...` path from the SSG build.\n */\n excludeDefaultLocaleFromIntlPaths?: boolean;\n}\n\nexport interface RootRedirectConfig {\n /**\n * The source path to redirect. Accepts placeholders in the format\n * `[key]` or `[...key]`. Use `[key]` for single segments and\n * `[...key]` for multi-segment wildcards.\n * @example \"/old-path/[id]\" or \"/old-path/[...wildcard]\"\n */\n source: string;\n\n /**\n * The destination to redirect to. Placeholders from the source can\n * optionally be inserted into the destination using the same\n * placeholder format.\n * @example \"/new-path/[id]\" or \"/new-path/[...wildcard]\"\n */\n destination: string;\n\n /**\n * The redirect type (`301` = permanent, `302` = temporary). If unspecified,\n * defaults to `302` (temporary).\n */\n type?: 301 | 302;\n}\n\nexport interface RootHeaderConfig {\n /** A glob pattern match (regex not supported yet). */\n source: string;\n headers: Array<{\n key: string;\n value: string;\n }>;\n}\n\nexport interface ContentSecurityPolicyConfig {\n directives?: Record<string, string[]>;\n reportOnly?: boolean;\n}\n\nexport interface XFrameOptionsConfig {\n action: 'DENY' | 'SAMEORIGIN';\n}\n\nexport interface RootSecurityConfig {\n /**\n * Content-Security-Policy config. If enabled, a nonce is auto-generated\n * for every request and appended to script and stylesheet tags. You can\n * validate your CSP headers using a tool like {@link https://csp-evaluator.withgoogle.com/}.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP}\n */\n contentSecurityPolicy?: ContentSecurityPolicyConfig | boolean;\n\n /**\n * Strict-Transport-Security config. When enabled, the header value is set\n * to `Strict-Transport-Security: max-age=63072000; includeSubDomains; preload`.\n */\n strictTransportSecurity?: boolean;\n\n /**\n * X-Content-Type-Options config. When enabled, the header value is set to\n * `X-Content-Type-Options: nosniff`.\n */\n xContentTypeOptions?: boolean;\n\n /**\n * X-Frame-Options config. Setting this value to `true` will default the\n * header value to `X-Frame-Options: SAMEORIGIN`.\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options}\n */\n xFrameOptions?: 'DENY' | 'SAMEORIGIN' | boolean;\n\n /**\n * X-XSS-Protection config. When enabled, the header value is set to\n * `X-XSS-Protection: 1; mode=block`.\n */\n xXssProtection?: boolean;\n}\n\nexport interface RootServerConfig {\n /**\n * An array of middleware to add to the express server. These middleware are\n * added to the beginning of the express app.\n */\n middlewares?: RequestMiddleware[];\n\n /**\n * The `trailingSlash` config allows you to control how the server handles\n * trailing slashes. This config only affects URLs that do not have a file\n * extension (i.e. HTML paths).\n *\n * - When `true`, the server redirects URLs to add a trailing slash\n * - When `false`, the server redirects URLs to remove a trailing slash\n * - When unspecified, the server allows URLs with and without trailing slash\n */\n trailingSlash?: boolean;\n\n /**\n * Cookie secret for the session middleware.\n *\n * Generate a secure secret with:\n * ```\n * node -e \"console.log(require('crypto').randomBytes(32).toString('hex'))\"\n * ```\n */\n sessionCookieSecret?: string | string[];\n\n /**\n * List of redirects. Supports optional wildcards.\n *\n * @example\n * ```ts\n * redirects: [\n * {\n * source: '/old-path/[id]',\n * destination: '/new-path/[id]',\n * type: 301,\n * },\n * {\n * source: '/old-path/[...wildcard]',\n * destination: '/new-path/[...wildcard]',\n * },\n * ]\n * ```\n */\n redirects?: RootRedirectConfig[];\n\n /**\n * HTTP headers to add to a response.\n */\n headers?: RootHeaderConfig[];\n\n /**\n * HTTP security settings. By default, all security settings are enabled with\n * commonly used default values.\n */\n security?: RootSecurityConfig;\n\n /**\n * Home page URL path, which is printed when the dev server starts.\n */\n homePagePath?: string;\n}\n\nexport function defineConfig(config: RootUserConfig): RootUserConfig {\n return config;\n}\n", "import {ComponentChildren, FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type BodyProps = preact.JSX.HTMLAttributes<HTMLBodyElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The `<Body>` component can be used to update attrs in the `<body>` tag.\n *\n * Usage:\n *\n * ```tsx\n * <Body className=\"body\">\n * <h1>Hello world</h1>\n * </Body>\n * ```\n *\n * Output:\n *\n * ```html\n * <body class=\"body\">\n * <h1>Hello world</h1>\n * </body>\n */\nexport const Body: FunctionalComponent<BodyProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Body> component'\n );\n }\n context.bodyAttrs = attrs;\n return <>{children}</>;\n};\n", "import {ComponentChildren, FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type HeadProps = preact.JSX.HTMLAttributes<HTMLHeadElement> & {\n children?: ComponentChildren;\n};\n\n/**\n * The <Head> component can be used for injecting elements into the HTML head\n * tag from any part of a page. The <Head> can be added via any component or\n * sub-component and will automatically be hoisted to the `<head>` element.\n *\n * Usage:\n *\n * ```tsx\n * <Head>\n * <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n * </Head>\n * ```\n */\nexport const Head: FunctionalComponent<HeadProps> = ({children, ...attrs}) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Head> component'\n );\n }\n context.headComponents.push(children);\n context.headAttrs = attrs;\n return null;\n};\n", "import {FunctionalComponent} from 'preact';\nimport {useContext} from 'preact/hooks';\nimport {HTML_CONTEXT} from './Html.js';\n\nexport type ScriptProps = preact.JSX.HTMLAttributes<HTMLScriptElement> & {\n // Cast the \"src\" attr to string. See:\n // https://github.com/blinkk/rootjs/issues/519\n src?: string;\n};\n\n/**\n * The <Script> component is used for rendering any custom script modules. At\n * the moment, the system only pre-renders and bundles files that are in the\n * `/bundles` folder at the root of the project.\n *\n * Usage:\n *\n * ```tsx\n * <Script src=\"/bundles/main.ts\" />\n * ```\n */\nexport const Script: FunctionalComponent<ScriptProps> = (props) => {\n const context = useContext(HTML_CONTEXT);\n if (!context) {\n throw new Error(\n 'HTML_CONTEXT not found, double-check usage of the <Script> component'\n );\n }\n context.scriptDeps.push(props);\n return null;\n};\n", "import {ComponentChildren, FunctionalComponent, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\nexport type StringParamsContext = Record<string, string>;\n\nexport const STRING_PARAMS_CONTEXT = createContext<StringParamsContext | null>(\n null\n);\n\nexport interface StringParamsProviderProps {\n value?: StringParamsContext;\n children?: ComponentChildren;\n}\n\nexport const StringParamsProvider: FunctionalComponent<\n StringParamsProviderProps\n> = (props) => {\n // Allow for nested param values from parent content providers.\n const parent = useContext(STRING_PARAMS_CONTEXT) || {};\n const merged = {...parent, ...props.value};\n return (\n <STRING_PARAMS_CONTEXT.Provider value={merged}>\n {props.children}\n </STRING_PARAMS_CONTEXT.Provider>\n );\n};\n\n/**\n * A hook that returns a map of string params, configured via the\n * `StringParamsProvider` context provider. These params are automatically\n * applied to the `useTranslations()` hook.\n *\n *\n * Usage:\n *\n * ```\n * export default function Page() {\n * return (\n * <StringParamsProvider value={{name: 'Alice'}}>\n * <SayHello />\n * </StringParamsProvider>\n * );\n * }\n *\n * function SayHello() {\n * const t = useTranslations();\n * return <h1>{t('Hello, {name}!')}</h1>;\n * }\n * ```\n *\n * This should render `<h1>Hello, Alice!</h1>`.\n */\nexport function useStringParams() {\n return useContext(STRING_PARAMS_CONTEXT) || {};\n}\n", "import {ComponentChildren, FunctionalComponent, createContext} from 'preact';\nimport {useContext} from 'preact/hooks';\n\ntype TransformFn = (str: string) => string;\n\nexport interface TranslationMiddleware {\n /** Transform the string before translation lookup. */\n beforeTranslate?: TransformFn;\n /** Transform the string after translation lookup. */\n afterTranslate?: TransformFn;\n /** Transform the string before `{param}` values are replaced. */\n beforeReplaceParams?: TransformFn;\n /** Transform the string after `{param}` values are replaced. */\n afterReplaceParams?: TransformFn;\n}\n\nexport interface TranslationMiddlewareContext {\n beforeTranslateFns: TransformFn[];\n afterTranslateFns: TransformFn[];\n beforeReplaceParamsFns: TransformFn[];\n afterReplaceParamsFns: TransformFn[];\n}\n\nconst TRANSLATION_MIDDLEWARE_CONTEXT =\n createContext<TranslationMiddlewareContext | null>(null);\n\nexport interface TranslationMiddlewareProviderProps {\n value?: TranslationMiddleware;\n children?: ComponentChildren;\n}\n\nexport const TranslationMiddlewareProvider: FunctionalComponent<\n TranslationMiddlewareProviderProps\n> = (props) => {\n const parent = useContext(TRANSLATION_MIDDLEWARE_CONTEXT) || {\n beforeTranslateFns: [],\n afterTranslateFns: [],\n beforeReplaceParamsFns: [],\n afterReplaceParamsFns: [],\n };\n const merged: TranslationMiddlewareContext = {\n beforeTranslateFns: [...parent.beforeTranslateFns],\n afterTranslateFns: [...parent.afterTranslateFns],\n beforeReplaceParamsFns: [...parent.beforeReplaceParamsFns],\n afterReplaceParamsFns: [...parent.afterReplaceParamsFns],\n };\n if (props.value?.beforeTranslate) {\n merged.beforeTranslateFns.push(props.value.beforeTranslate);\n }\n if (props.value?.afterTranslate) {\n merged.afterTranslateFns.push(props.value.afterTranslate);\n }\n if (props.value?.beforeReplaceParams) {\n merged.beforeReplaceParamsFns.push(props.value.beforeReplaceParams);\n }\n if (props.value?.afterReplaceParams) {\n merged.afterReplaceParamsFns.push(props.value.afterReplaceParams);\n }\n return (\n <TRANSLATION_MIDDLEWARE_CONTEXT.Provider value={merged}>\n {props.children}\n </TRANSLATION_MIDDLEWARE_CONTEXT.Provider>\n );\n};\n\nexport function useTranslationMiddleware(): TranslationMiddlewareContext {\n return (\n useContext(TRANSLATION_MIDDLEWARE_CONTEXT) || {\n beforeTranslateFns: [],\n afterTranslateFns: [],\n beforeReplaceParamsFns: [],\n afterReplaceParamsFns: [],\n }\n );\n}\n", "import {I18nContext, useI18nContext} from './useI18nContext.js';\nimport {useStringParams} from './useStringParams.js';\nimport {useTranslationMiddleware} from './useTranslationsMiddleware.js';\n\n/**\n * A hook that returns a function that can be used to translate a string, and\n * optionally replace any parameterized values that are surrounded in curly\n * braces.\n *\n * Usage:\n *\n * ```ts\n * const t = useTranslations();\n * t('Hello {name}', {name: 'Bob'});\n * // => 'Bounjour Bob'\n * ```\n */\nexport function useTranslations() {\n // Ignore I18nContext not found error when used with client-side rehydration.\n let i18nContext: I18nContext | null = null;\n try {\n i18nContext = useI18nContext();\n } catch {\n console.warn('I18nContext not found');\n }\n const translations = i18nContext?.translations || {};\n const stringParams = useStringParams();\n const middleware = useTranslationMiddleware();\n\n function t(str: string, params?: Record<string, string | number>): string;\n function t(\n str: string | null | undefined,\n params?: Record<string, string | number>\n ): string | undefined {\n // Suppress verbatim `'undefined'` and `'null'` output, which can occur when\n // using `useTranslations` with undefined values.\n if (typeof str === 'undefined' || str === null) {\n // Return `undefined` to suppress empty props, e.g.\n // <a title={t(undefined)}>Learn more</a>\n return undefined;\n }\n let input = normalizeString(str);\n middleware.beforeTranslateFns.forEach((fn) => {\n input = fn(input);\n });\n let translation = translations[input] ?? input ?? '';\n middleware.afterTranslateFns.forEach((fn) => {\n translation = fn(translation);\n });\n\n // Replace string params, e.g. \"Hello, {name}\".\n middleware.beforeReplaceParamsFns.forEach((fn) => {\n translation = fn(translation);\n });\n if (testHasStringParams(translation)) {\n translation = replaceStringParams(translation, {\n ...stringParams,\n ...params,\n });\n }\n middleware.afterReplaceParamsFns.forEach((fn) => {\n translation = fn(translation);\n });\n\n return translation;\n }\n return t;\n}\n\n/**\n * Cleans a string that's used for translations. Performs the following:\n * - Removes any leading/trailing whitespace\n * - Removes spaces at the end of any line\n */\nexport function normalizeString(str: string) {\n const lines = String(str)\n .trim()\n .split('\\n')\n .map((line) => removeTrailingWhitespace(line));\n return lines.join('\\n');\n}\n\nfunction removeTrailingWhitespace(str: string) {\n return String(str)\n .trimEnd()\n .replace(/ $/, '');\n}\n\nfunction testHasStringParams(str: string) {\n return str.includes('{') && str.includes('}');\n}\n\n/**\n * Replaces string placeholder params, e.g.\n *\n * ```\n * replaceStringParams('Hello, {name}!', {name: 'Joe'})\n * // => 'Hello, Joe!'\n * ```\n */\nfunction replaceStringParams(\n str: string,\n params: Record<string, string | number>\n): string {\n return str.replace(/{([^}]+)}/g, (match, key) => {\n if (key in params) {\n return String(params[key]);\n }\n return match;\n });\n}\n", "import {PluginOption as VitePlugin} from 'vite';\nimport {RootConfig} from './config.js';\n\nexport interface Pod {\n /** Unique pod name, e.g. '@blinkk/root-docs-pod'. */\n name: string;\n\n /**\n * URL prefix for pod routes. Routes within the pod are served under this\n * mount path. Defaults to '/'.\n */\n mount?: string;\n\n /**\n * Priority for route conflict resolution. Higher values win when multiple\n * pods register the same URL path. User-site routes always take precedence\n * regardless of priority. Defaults to 0.\n */\n priority?: number;\n\n /** Absolute path to the pod's routes/ directory. */\n routesDir?: string;\n\n /** Absolute path(s) to the pod's elements/ directory(s). */\n elementsDirs?: string[];\n\n /** Absolute path to the pod's bundles/ directory. */\n bundlesDir?: string;\n\n /** Absolute path to the pod's collections/ directory (root-cms only). */\n collectionsDir?: string;\n\n /** Absolute path to the pod's translations/ directory. */\n translationsDir?: string;\n\n /** Extra Vite plugins contributed by the pod. */\n vitePlugins?: VitePlugin[];\n}\n\nexport type PodFactory = (ctx: {rootConfig: RootConfig}) => Pod | Promise<Pod>;\n\nexport interface PodConfig {\n /** Whether the pod is enabled. Defaults to true. */\n enabled?: boolean;\n\n /** Override the pod's mount path. */\n mount?: string;\n\n /** Override the pod's priority. */\n priority?: number;\n\n /** Filter pod routes. */\n routes?: {\n exclude?: (string | RegExp)[];\n };\n\n /** Configure pod collections. */\n collections?: {\n exclude?: string[];\n /** Rename collection ids, e.g. {Posts: 'DocsPosts'}. */\n rename?: Record<string, string>;\n };\n}\n\n/**\n * Helper to define a pod with type-checking.\n */\nexport function definePod(pod: Pod): Pod {\n return pod;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["useContext", "useContext", "useContext", "useContext", "useContext", "jsx", "createContext", "useContext", "jsx"]
|
|
7
7
|
}
|
|
@@ -7,4 +7,4 @@ export interface ProdServerOptions {
|
|
|
7
7
|
/**
|
|
8
8
|
* Firebase Function that runs a Root.js server running in SSR mode.
|
|
9
9
|
*/
|
|
10
|
-
export declare function server(options?: ProdServerOptions): import("firebase-functions/
|
|
10
|
+
export declare function server(options?: ProdServerOptions): import("firebase-functions/https").HttpsFunction;
|
package/dist/functions.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createPreviewServer,
|
|
3
3
|
createProdServer
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-WRZLI2L2.js";
|
|
5
|
+
import "./chunk-QJ4F45DC.js";
|
|
6
6
|
import "./chunk-I3RCAIW7.js";
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-DLPHCMFV.js";
|
|
8
|
+
import "./chunk-Y4H75NIO.js";
|
|
9
9
|
import "./chunk-3PWR4F2R.js";
|
|
10
10
|
import "./chunk-XSNCF7WU.js";
|
|
11
11
|
import "./chunk-TM6QRBGS.js";
|
package/dist/node.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
createViteServer,
|
|
4
4
|
invalidatePodCache,
|
|
5
5
|
viteSsrLoadModule
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QJ4F45DC.js";
|
|
7
7
|
import {
|
|
8
8
|
bundleRootConfig,
|
|
9
9
|
flattenPackageDepsFromMonorepo,
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
loadPackageJson,
|
|
13
13
|
loadRootConfig,
|
|
14
14
|
loadRootConfigWithDeps
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-Y4H75NIO.js";
|
|
16
16
|
import "./chunk-XSNCF7WU.js";
|
|
17
17
|
export {
|
|
18
18
|
bundleRootConfig,
|
|
@@ -15,11 +15,18 @@ export interface Asset {
|
|
|
15
15
|
* Recursively walks all deps and returns a list of JS asset URLs.
|
|
16
16
|
*/
|
|
17
17
|
getJsDeps(): Promise<string[]>;
|
|
18
|
+
/**
|
|
19
|
+
* Recursively walks all deps and returns a list of JS chunk URLs that the
|
|
20
|
+
* browser loads as a result of importing this asset. The asset's own URL is
|
|
21
|
+
* excluded. These URLs are injected as `<link rel="modulepreload">` tags
|
|
22
|
+
* when `modulePreload` is enabled in `root.config.ts`.
|
|
23
|
+
*/
|
|
24
|
+
getModulePreloadDeps(): Promise<string[]>;
|
|
18
25
|
}
|
|
19
26
|
export interface AssetMap {
|
|
20
27
|
/**
|
|
21
28
|
* Returns the asset for a given src file. The `src` value should be a path
|
|
22
29
|
* relative to the project root, e.g. "routes/index.tsx".
|
|
23
30
|
*/
|
|
24
|
-
get: (src: string) =>
|
|
31
|
+
get: (src: string) => Asset | null;
|
|
25
32
|
}
|
|
@@ -23,7 +23,8 @@ export declare class BuildAssetMap implements AssetMap {
|
|
|
23
23
|
private rootConfig;
|
|
24
24
|
private srcToAsset;
|
|
25
25
|
constructor(rootConfig: RootConfig);
|
|
26
|
-
get(src: string):
|
|
26
|
+
get(src: string): Asset | null;
|
|
27
|
+
private find;
|
|
27
28
|
private add;
|
|
28
29
|
toJson(): BuildAssetManifest;
|
|
29
30
|
static fromViteManifest(rootConfig: RootConfig, clientManifest: Manifest, elementsGraph: ElementGraph, podRoutes?: PodRouteAsset[]): BuildAssetMap;
|
|
@@ -45,7 +46,13 @@ export declare class BuildAsset {
|
|
|
45
46
|
});
|
|
46
47
|
getCssDeps(): Promise<string[]>;
|
|
47
48
|
getJsDeps(): Promise<string[]>;
|
|
49
|
+
getModulePreloadDeps(): Promise<string[]>;
|
|
48
50
|
private collectJs;
|
|
51
|
+
/**
|
|
52
|
+
* Walks `srcs` and their transitive imports, collecting the JS chunk URL of
|
|
53
|
+
* every module along the way.
|
|
54
|
+
*/
|
|
55
|
+
private collectModulePreload;
|
|
49
56
|
private collectCss;
|
|
50
57
|
toJson(): {
|
|
51
58
|
src: string;
|
|
@@ -5,7 +5,7 @@ export declare class DevServerAssetMap implements AssetMap {
|
|
|
5
5
|
private rootConfig;
|
|
6
6
|
private moduleGraph;
|
|
7
7
|
constructor(rootConfig: RootConfig, moduleGraph: ModuleGraph);
|
|
8
|
-
get(src: string):
|
|
8
|
+
get(src: string): Asset | null;
|
|
9
9
|
filePathToSrc(file: string): string;
|
|
10
10
|
}
|
|
11
11
|
export declare class DevServerAsset implements Asset {
|
|
@@ -20,6 +20,12 @@ export declare class DevServerAsset implements Asset {
|
|
|
20
20
|
});
|
|
21
21
|
getCssDeps(): Promise<string[]>;
|
|
22
22
|
getJsDeps(): Promise<string[]>;
|
|
23
|
+
/**
|
|
24
|
+
* The dev server serves modules unbundled and unhashed, so there are no
|
|
25
|
+
* shared chunks to preload. Returning an empty list keeps
|
|
26
|
+
* `<link rel="modulepreload">` tags out of the dev server's HTML.
|
|
27
|
+
*/
|
|
28
|
+
getModulePreloadDeps(): Promise<string[]>;
|
|
23
29
|
getImportedModules(): Set<ModuleNode>;
|
|
24
30
|
private collectJs;
|
|
25
31
|
private collectCss;
|
package/dist/render/render.d.ts
CHANGED
|
@@ -90,7 +90,9 @@ export declare class Renderer {
|
|
|
90
90
|
}>;
|
|
91
91
|
/**
|
|
92
92
|
* Parses rendered HTML for custom element tags used on the page and
|
|
93
|
-
* automatically adds the JS/CSS deps to the page.
|
|
93
|
+
* automatically adds the JS/CSS deps to the page. When `preloadDeps` is
|
|
94
|
+
* provided, the chunks imported by those elements are collected into it for
|
|
95
|
+
* `<link rel="modulepreload">` injection.
|
|
94
96
|
*/
|
|
95
97
|
private collectElementDeps;
|
|
96
98
|
/**
|
package/dist/render.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ASSET_MAP_CONTEXT,
|
|
2
3
|
HTML_CONTEXT,
|
|
3
4
|
I18N_CONTEXT,
|
|
4
5
|
REQUEST_CONTEXT,
|
|
5
6
|
getTranslations,
|
|
6
7
|
replaceParams,
|
|
7
8
|
testPathHasParams
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6QWKKJOB.js";
|
|
9
10
|
import {
|
|
10
11
|
RouteTrie
|
|
11
12
|
} from "./chunk-I3RCAIW7.js";
|
|
@@ -13186,7 +13187,7 @@ var Renderer = class {
|
|
|
13186
13187
|
bodyAttrs: {},
|
|
13187
13188
|
scriptDeps: []
|
|
13188
13189
|
};
|
|
13189
|
-
const vdom = /* @__PURE__ */ jsx4(REQUEST_CONTEXT.Provider, { value: ctx, children: /* @__PURE__ */ jsx4(I18N_CONTEXT.Provider, { value: { locale, translations }, children: /* @__PURE__ */ jsx4(HTML_CONTEXT.Provider, { value: htmlContext, children: /* @__PURE__ */ jsx4(Component, { ...props }) }) }) });
|
|
13190
|
+
const vdom = /* @__PURE__ */ jsx4(ASSET_MAP_CONTEXT.Provider, { value: this.assetMap, children: /* @__PURE__ */ jsx4(REQUEST_CONTEXT.Provider, { value: ctx, children: /* @__PURE__ */ jsx4(I18N_CONTEXT.Provider, { value: { locale, translations }, children: /* @__PURE__ */ jsx4(HTML_CONTEXT.Provider, { value: htmlContext, children: /* @__PURE__ */ jsx4(Component, { ...props }) }) }) }) });
|
|
13190
13191
|
const renderJsxFn = await this.getJsxRenderFn({ mode: options.renderMode });
|
|
13191
13192
|
const preactHook = preactOptions.vnode;
|
|
13192
13193
|
let mainHtml;
|
|
@@ -13211,6 +13212,7 @@ var Renderer = class {
|
|
|
13211
13212
|
}
|
|
13212
13213
|
const jsDeps = /* @__PURE__ */ new Set();
|
|
13213
13214
|
const cssDeps = /* @__PURE__ */ new Set();
|
|
13215
|
+
const preloadDeps = this.rootConfig.modulePreload ? /* @__PURE__ */ new Set() : null;
|
|
13214
13216
|
const routeAsset = await this.assetMap.get(route.src);
|
|
13215
13217
|
if (routeAsset) {
|
|
13216
13218
|
const routeCssDeps = await routeAsset.getCssDeps();
|
|
@@ -13224,7 +13226,7 @@ var Renderer = class {
|
|
|
13224
13226
|
this.getConfiguredStyleEntries().forEach((styleEntry) => {
|
|
13225
13227
|
cssDeps.add(styleEntry);
|
|
13226
13228
|
});
|
|
13227
|
-
await this.collectElementDeps(mainHtml, jsDeps, cssDeps);
|
|
13229
|
+
await this.collectElementDeps(mainHtml, jsDeps, cssDeps, preloadDeps);
|
|
13228
13230
|
await Promise.all(
|
|
13229
13231
|
htmlContext.scriptDeps.map(async (scriptDep) => {
|
|
13230
13232
|
if (!scriptDep.src) {
|
|
@@ -13236,12 +13238,19 @@ var Renderer = class {
|
|
|
13236
13238
|
jsDeps.add(scriptAsset.assetUrl);
|
|
13237
13239
|
const scriptJsDeps = await scriptAsset.getJsDeps();
|
|
13238
13240
|
scriptJsDeps.forEach((dep) => jsDeps.add(dep));
|
|
13241
|
+
if (preloadDeps) {
|
|
13242
|
+
const scriptPreloadDeps = await scriptAsset.getModulePreloadDeps();
|
|
13243
|
+
scriptPreloadDeps.forEach((dep) => preloadDeps.add(dep));
|
|
13244
|
+
}
|
|
13239
13245
|
}
|
|
13240
13246
|
})
|
|
13241
13247
|
);
|
|
13242
13248
|
const styleTags = Array.from(cssDeps).map((cssUrl) => {
|
|
13243
13249
|
return /* @__PURE__ */ jsx4("link", { rel: "stylesheet", href: cssUrl, nonce });
|
|
13244
13250
|
});
|
|
13251
|
+
const preloadTags = Array.from(preloadDeps || []).filter((jsUrl) => !jsDeps.has(jsUrl)).map((jsUrl) => {
|
|
13252
|
+
return /* @__PURE__ */ jsx4("link", { rel: "modulepreload", href: jsUrl, nonce });
|
|
13253
|
+
});
|
|
13245
13254
|
const scriptTags = Array.from(jsDeps).map((jsUrls) => {
|
|
13246
13255
|
if (this.rootConfig.experiments?.enableScriptAsync) {
|
|
13247
13256
|
return /* @__PURE__ */ jsx4("script", { type: "module", src: jsUrls, nonce, async: true });
|
|
@@ -13255,6 +13264,7 @@ var Renderer = class {
|
|
|
13255
13264
|
headComponents: [
|
|
13256
13265
|
...htmlContext.headComponents,
|
|
13257
13266
|
...styleTags,
|
|
13267
|
+
...preloadTags,
|
|
13258
13268
|
...scriptTags
|
|
13259
13269
|
],
|
|
13260
13270
|
renderMode: options.renderMode
|
|
@@ -13682,9 +13692,11 @@ ${content}`;
|
|
|
13682
13692
|
}
|
|
13683
13693
|
/**
|
|
13684
13694
|
* Parses rendered HTML for custom element tags used on the page and
|
|
13685
|
-
* automatically adds the JS/CSS deps to the page.
|
|
13695
|
+
* automatically adds the JS/CSS deps to the page. When `preloadDeps` is
|
|
13696
|
+
* provided, the chunks imported by those elements are collected into it for
|
|
13697
|
+
* `<link rel="modulepreload">` injection.
|
|
13686
13698
|
*/
|
|
13687
|
-
async collectElementDeps(html, jsDeps, cssDeps) {
|
|
13699
|
+
async collectElementDeps(html, jsDeps, cssDeps, preloadDeps) {
|
|
13688
13700
|
const elementsMap = this.elementGraph.sourceFiles;
|
|
13689
13701
|
const assetMap = this.assetMap;
|
|
13690
13702
|
const tagNames = /* @__PURE__ */ new Set();
|
|
@@ -13705,6 +13717,10 @@ ${content}`;
|
|
|
13705
13717
|
}
|
|
13706
13718
|
const assetJsDeps = await asset.getJsDeps();
|
|
13707
13719
|
assetJsDeps.forEach((dep) => jsDeps.add(dep));
|
|
13720
|
+
if (preloadDeps) {
|
|
13721
|
+
const assetPreloadDeps = await asset.getModulePreloadDeps();
|
|
13722
|
+
assetPreloadDeps.forEach((dep) => preloadDeps.add(dep));
|
|
13723
|
+
}
|
|
13708
13724
|
const assetCssDeps = await asset.getCssDeps();
|
|
13709
13725
|
assetCssDeps.forEach((dep) => {
|
|
13710
13726
|
if (dep.endsWith("?inline")) {
|