Skip to content

Commit

Permalink
feat: config hmr support for routeRules and rutimeConfig (#1175)
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 authored Apr 19, 2023
1 parent 5c92dc3 commit b320208
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 66 deletions.
2 changes: 2 additions & 0 deletions src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,8 @@ async function _watch(nitro: Nitro, rollupConfig: RollupConfig) {
reloadWacher.close();
});

nitro.hooks.hook("rollup:reload", () => reload());

await reload();
}

Expand Down
11 changes: 9 additions & 2 deletions src/cli/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { createDevServer } from "../../dev/server";
import { commonArgs } from "../common";
import type { Nitro } from "../../types";

const hmrKeyRe = /^runtimeConfig\.|routeRules\./;

export default defineCommand({
meta: {
name: "dev",
Expand Down Expand Up @@ -35,16 +37,21 @@ export default defineCommand({
{
watch: true,
c12: {
async onUpdate({ getDiff }) {
async onUpdate({ getDiff, newConfig }) {
const diff = getDiff();

if (diff.length === 0) {
return; // No changes
}

consola.info(
"Nitro config updated:\n" +
diff.map((entry) => ` ${entry.toString()}`).join("\n")
);
await reload();

await (!diff.every((e) => hmrKeyRe.test(e.key))
? reload() // Full reload
: nitro.updateConfig(newConfig.config)); // Hot reload
},
},
}
Expand Down
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ export * from "./build";
export * from "./nitro";
export * from "./scan";
export * from "./dev/server";
export * from "./options";
export * from "./types";
export * from "./prerender";
export * from "./preset";

export { loadOptions } from "./options";
export type { LoadConfigOptions } from "./options";
19 changes: 17 additions & 2 deletions src/nitro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ import { createHooks, createDebugger } from "hookable";
import { createUnimport } from "unimport";
import { defu } from "defu";
import { consola } from "consola";
import type { NitroConfig, Nitro } from "./types";
import { LoadConfigOptions, loadOptions } from "./options";
import type { NitroConfig, Nitro, NitroDynamicConfig } from "./types";
import {
LoadConfigOptions,
loadOptions,
normalizeRouteRules,
normalizeRuntimeConfig,
} from "./options";
import { scanPlugins } from "./scan";
import { createStorage } from "./storage";

Expand All @@ -25,6 +30,16 @@ export async function createNitro(
scannedHandlers: [],
close: () => nitro.hooks.callHook("close"),
storage: undefined,
async updateConfig(config: NitroDynamicConfig) {
nitro.options.routeRules = normalizeRouteRules(
config.routeRules ? config : nitro.options
);
nitro.options.runtimeConfig = normalizeRuntimeConfig(
config.runtimeConfig ? config : nitro.options
);
await nitro.hooks.callHook("rollup:reload");
consola.success("Nitro config hot reloaded!");
},
};

// Storage
Expand Down
132 changes: 72 additions & 60 deletions src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,10 +281,77 @@ export async function loadOptions(
// Backward compatibility for options.routes
options.routeRules = defu(options.routeRules, (options as any).routes || {});

// Normalize route rules (NitroRouteConfig => NitroRouteRules)
const normalizedRules: { [p: string]: NitroRouteRules } = {};
for (const path in options.routeRules) {
const routeConfig = options.routeRules[path] as NitroRouteConfig;
// Normalize route rules
options.routeRules = normalizeRouteRules(options);

options.baseURL = withLeadingSlash(withTrailingSlash(options.baseURL));

// Normalize runtime config
options.runtimeConfig = normalizeRuntimeConfig(options);

for (const publicAsset of options.publicAssets) {
publicAsset.dir = resolve(options.srcDir, publicAsset.dir);
publicAsset.baseURL = withLeadingSlash(
withoutTrailingSlash(publicAsset.baseURL || "/")
);
}

for (const serverAsset of options.serverAssets) {
serverAsset.dir = resolve(options.srcDir, serverAsset.dir);
}

for (const pkg of ["defu", "h3", "radix3"]) {
if (!options.alias[pkg]) {
options.alias[pkg] = await resolveModule(pkg, { url: import.meta.url });
}
}

// Build-only storage
const fsMounts = {
root: resolve(options.rootDir),
src: resolve(options.srcDir),
build: resolve(options.buildDir),
cache: resolve(options.buildDir, "cache"),
};
for (const p in fsMounts) {
options.devStorage[p] = options.devStorage[p] || {
driver: "fs",
readOnly: p === "root" || p === "src",
base: fsMounts[p],
};
}

// Resolve plugin paths
options.plugins = options.plugins.map((p) => resolvePath(p, options));

return options;
}

/**
* @deprecated Please import `defineNitroConfig` from nitropack/config instead
*/
export function defineNitroConfig(config: NitroConfig): NitroConfig {
return config;
}

export function normalizeRuntimeConfig(config: NitroConfig) {
provideFallbackValues(config.runtimeConfig);
const runtimeConfig = defu(config.runtimeConfig, {
app: {
baseURL: config.baseURL,
},
nitro: {},
});
runtimeConfig.nitro.routeRules = config.routeRules;
return runtimeConfig;
}

export function normalizeRouteRules(
config: NitroConfig
): Record<string, NitroRouteRules> {
const normalizedRules: Record<string, NitroRouteRules> = {};
for (const path in config.routeRules) {
const routeConfig = config.routeRules[path] as NitroRouteConfig;
const routeRules: NitroRouteRules = {
...routeConfig,
redirect: undefined,
Expand Down Expand Up @@ -335,60 +402,5 @@ export async function loadOptions(
}
normalizedRules[path] = routeRules;
}
options.routeRules = normalizedRules;

options.baseURL = withLeadingSlash(withTrailingSlash(options.baseURL));

provideFallbackValues(options.runtimeConfig);
options.runtimeConfig = defu(options.runtimeConfig, {
app: {
baseURL: options.baseURL,
},
nitro: {},
});
options.runtimeConfig.nitro.routeRules = options.routeRules;

for (const publicAsset of options.publicAssets) {
publicAsset.dir = resolve(options.srcDir, publicAsset.dir);
publicAsset.baseURL = withLeadingSlash(
withoutTrailingSlash(publicAsset.baseURL || "/")
);
}

for (const serverAsset of options.serverAssets) {
serverAsset.dir = resolve(options.srcDir, serverAsset.dir);
}

for (const pkg of ["defu", "h3", "radix3"]) {
if (!options.alias[pkg]) {
options.alias[pkg] = await resolveModule(pkg, { url: import.meta.url });
}
}

// Build-only storage
const fsMounts = {
root: resolve(options.rootDir),
src: resolve(options.srcDir),
build: resolve(options.buildDir),
cache: resolve(options.buildDir, "cache"),
};
for (const p in fsMounts) {
options.devStorage[p] = options.devStorage[p] || {
driver: "fs",
readOnly: p === "root" || p === "src",
base: fsMounts[p],
};
}

// Resolve plugin paths
options.plugins = options.plugins.map((p) => resolvePath(p, options));

return options;
}

/**
* @deprecated Please import `defineNitroConfig` from nitropack/config instead
*/
export function defineNitroConfig(config: NitroConfig): NitroConfig {
return config;
return normalizedRules;
}
3 changes: 2 additions & 1 deletion src/rollup/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ export const getRollupConfig = (nitro: Nitro): RollupConfig => {
server: true,
client: false,
dev: String(nitro.options.dev),
RUNTIME_CONFIG: nitro.options.runtimeConfig,
DEBUG: nitro.options.dev,
};

Expand All @@ -183,6 +182,8 @@ export const getRollupConfig = (nitro: Nitro): RollupConfig => {
values: {
"typeof window": '"undefined"',
_import_meta_url_: "import.meta.url",
"process.env.RUNTIME_CONFIG": () =>
JSON.stringify(nitro.options.runtimeConfig, null, 2),
...Object.fromEntries(
[".", ";", ")", "[", "]", "}", " "].map((d) => [
`import.meta${d}`,
Expand Down
7 changes: 7 additions & 0 deletions src/types/nitro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import type {
import type { PresetOptions } from "./presets";
import type { KebabCase } from "./utils";

export type NitroDynamicConfig = Pick<
NitroConfig,
"runtimeConfig" | "routeRules"
>;

export interface Nitro {
options: NitroOptions;
scannedHandlers: NitroEventHandler[];
Expand All @@ -34,6 +39,7 @@ export interface Nitro {
logger: ConsolaInstance;
storage: Storage;
close: () => Promise<void>;
updateConfig: (config: NitroDynamicConfig) => void | Promise<void>;

/* @internal */
_prerenderedRoutes?: PrerenderGenerateRoute[];
Expand All @@ -57,6 +63,7 @@ export interface NitroHooks {
"rollup:before": (nitro: Nitro, config: RollupConfig) => HookResult;
compiled: (nitro: Nitro) => HookResult;
"dev:reload": () => HookResult;
"rollup:reload": () => HookResult;
restart: () => HookResult;
close: () => HookResult;
"prerender:routes": (routes: Set<string>) => HookResult;
Expand Down

0 comments on commit b320208

Please sign in to comment.