defuss-ssg 0.6.2 → 0.7.0

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.
@@ -12,7 +12,7 @@ var defuss = require('defuss-vite');
12
12
  var node_module = require('node:module');
13
13
  var node_url = require('node:url');
14
14
  var node_os = require('node:os');
15
- var esbuild = require('esbuild');
15
+ var rolldown = require('rolldown');
16
16
  var rehypeKatex = require('rehype-katex');
17
17
  var rehypeStringify = require('rehype-stringify');
18
18
  var remarkFrontmatter = require('remark-frontmatter');
@@ -21,6 +21,7 @@ var remarkGfm = require('remark-gfm');
21
21
  var remarkParse = require('remark-parse');
22
22
  var remarkRehype = require('remark-rehype');
23
23
  var remarkMdxFrontmatter = require('remark-mdx-frontmatter');
24
+ var path = require('./path-Br3DXScZ.cjs');
24
25
 
25
26
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
26
27
  const defaultRemarkPlugins = [
@@ -32,26 +33,16 @@ const defaultRemarkPlugins = [
32
33
  remarkMath
33
34
  ];
34
35
  const defaultRehypePlugins = [rehypeKatex, rehypeStringify];
35
- const readConfig = async (projectDir, debug) => {
36
- const configPath = node_path.join(projectDir, "config.ts");
37
- let config = {};
38
- if (node_fs.existsSync(configPath)) {
39
- if (debug) {
40
- console.log(`Using config from ${configPath}`);
36
+ const resolveConfigPath = (projectDir) => {
37
+ for (const candidate of ["config.ts", "config.js"]) {
38
+ const configPath = node_path.join(projectDir, candidate);
39
+ if (node_fs.existsSync(configPath)) {
40
+ return configPath;
41
41
  }
42
- const result = await esbuild.build({
43
- entryPoints: [configPath],
44
- format: "esm",
45
- bundle: true,
46
- target: ["esnext"],
47
- write: false
48
- });
49
- const code = result.outputFiles[0].text;
50
- const tmpFile = node_path.join(node_os.tmpdir(), `defuss-ssg-config-${Date.now()}.mjs`);
51
- await promises.writeFile(tmpFile, code, "utf-8");
52
- const module = await import(tmpFile);
53
- config = module.default;
54
42
  }
43
+ return null;
44
+ };
45
+ const applyConfigDefaults = (config) => {
55
46
  config.pages = config.pages || configDefaults.pages;
56
47
  config.output = config.output || configDefaults.output;
57
48
  config.components = config.components || configDefaults.components;
@@ -61,8 +52,46 @@ const readConfig = async (projectDir, debug) => {
61
52
  config.remarkPlugins = config.remarkPlugins || configDefaults.remarkPlugins;
62
53
  config.rehypePlugins = config.rehypePlugins || configDefaults.rehypePlugins;
63
54
  config.rpc = config.rpc ?? configDefaults.rpc;
55
+ config.containerRuntime = config.containerRuntime ?? configDefaults.containerRuntime;
56
+ config.viteConfig = config.viteConfig ?? configDefaults.viteConfig;
64
57
  return config;
65
58
  };
59
+ const compileConfigModule = async (configPath, projectDir) => {
60
+ const tsconfigPath = node_path.join(projectDir, "tsconfig.json");
61
+ const result = await rolldown.build({
62
+ input: configPath,
63
+ cwd: projectDir,
64
+ platform: "node",
65
+ tsconfig: node_fs.existsSync(tsconfigPath) ? tsconfigPath : false,
66
+ output: {
67
+ format: "esm",
68
+ sourcemap: false
69
+ }
70
+ });
71
+ const chunk = result.output.find(
72
+ (output) => output.type === "chunk" && typeof output.code === "string"
73
+ );
74
+ if (!chunk) {
75
+ throw new Error(`Failed to compile SSG config: ${configPath}`);
76
+ }
77
+ return chunk.code;
78
+ };
79
+ const readConfig = async (projectDir, debug) => {
80
+ const resolvedProjectDir = node_path.resolve(projectDir);
81
+ const configPath = resolveConfigPath(resolvedProjectDir);
82
+ let config = {};
83
+ if (configPath) {
84
+ if (debug) {
85
+ console.log(`Using config from ${configPath}`);
86
+ }
87
+ const code = await compileConfigModule(configPath, resolvedProjectDir);
88
+ const tmpFile = node_path.join(node_os.tmpdir(), `defuss-ssg-config-${Date.now()}.mjs`);
89
+ await promises.writeFile(tmpFile, code, "utf-8");
90
+ const module = await import(tmpFile);
91
+ config = module.default;
92
+ }
93
+ return applyConfigDefaults(config);
94
+ };
66
95
  const configDefaults = {
67
96
  pages: "pages",
68
97
  output: "dist",
@@ -72,7 +101,77 @@ const configDefaults = {
72
101
  plugins: [],
73
102
  remarkPlugins: defaultRemarkPlugins,
74
103
  rehypePlugins: defaultRehypePlugins,
75
- rpc: true
104
+ rpc: true,
105
+ containerRuntime: void 0,
106
+ viteConfig: {}
107
+ };
108
+
109
+ const CONTENT_MODULE_ID = "virtual:defuss-ssg/content";
110
+ const CONTENT_RESOLVED_ID = "\0virtual:defuss-ssg/content";
111
+ const __filename$2 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite-BC7XxFTV.cjs', document.baseURI).href)));
112
+ const __dirname$2 = node_path.dirname(__filename$2);
113
+ const resolveContentHelperFile = () => {
114
+ const candidates = [
115
+ node_path.join(__dirname$2, "content.ts"),
116
+ node_path.join(__dirname$2, "..", "src", "content.ts"),
117
+ node_path.join(__dirname$2, "content.mjs")
118
+ ];
119
+ for (const candidate of candidates) {
120
+ if (node_fs.existsSync(candidate)) {
121
+ return candidate;
122
+ }
123
+ }
124
+ return node_path.resolve(__dirname$2, "content.mjs");
125
+ };
126
+ const resolveValue = (value) => typeof value === "function" ? value() : value;
127
+ const createContentModulePlugin = ({
128
+ projectDir,
129
+ pagesDir
130
+ }) => ({
131
+ name: "vite:defuss-ssg-content",
132
+ enforce: "pre",
133
+ resolveId(id) {
134
+ if (id === CONTENT_MODULE_ID) {
135
+ return CONTENT_RESOLVED_ID;
136
+ }
137
+ return null;
138
+ },
139
+ load(id) {
140
+ if (id !== CONTENT_RESOLVED_ID) {
141
+ return null;
142
+ }
143
+ const helperFilePath = resolveContentHelperFile();
144
+ const resolvedProjectDir = node_path.resolve(resolveValue(projectDir));
145
+ const resolvedPagesDir = resolveValue(pagesDir);
146
+ return [
147
+ `import { glob as rawGlob } from ${JSON.stringify(helperFilePath)};`,
148
+ `const defaultOptions = { cwd: ${JSON.stringify(resolvedProjectDir)}, pagesDir: ${JSON.stringify(resolvedPagesDir)} };`,
149
+ "export const glob = (patterns, options = {}) => rawGlob(patterns, { ...defaultOptions, ...options });"
150
+ ].join("\n");
151
+ }
152
+ });
153
+ const invalidateContentModule = (server, timestamp) => {
154
+ for (const environment of Object.values(server.environments)) {
155
+ const module = environment.moduleGraph.getModuleById(CONTENT_RESOLVED_ID);
156
+ if (!module) {
157
+ continue;
158
+ }
159
+ environment.moduleGraph.invalidateModule(
160
+ module,
161
+ /* @__PURE__ */ new Set(),
162
+ timestamp,
163
+ true
164
+ );
165
+ }
166
+ };
167
+ const hasContentModuleImporters = (server) => {
168
+ for (const environment of Object.values(server.environments)) {
169
+ const module = environment.moduleGraph.getModuleById(CONTENT_RESOLVED_ID);
170
+ if (module && module.importers.size > 0) {
171
+ return true;
172
+ }
173
+ }
174
+ return false;
76
175
  };
77
176
 
78
177
  const toStableHydrateId = (seed) => {
@@ -185,173 +284,6 @@ function applyAutoHydrate(vdom, componentsDir, componentsPublicPrefix, relativeO
185
284
  return processDefussComponents(vdom);
186
285
  }
187
286
 
188
- const DEFAULT_PAGES_DIR = "pages";
189
- const DEFAULT_COMPONENTS_DIR = "components";
190
- const DEFAULT_ASSETS_DIR = "assets";
191
- const COMPONENTS_SOURCE_ALIASES = [DEFAULT_COMPONENTS_DIR, "csr"];
192
- const PAGE_SOURCE_EXTENSIONS = [".mdx", ".md", ".html"];
193
- const normalizePath$2 = (filePath) => filePath.replace(/\\/g, "/");
194
- const isDefaultPath = (value, defaultValue) => normalizePath$2(value) === defaultValue;
195
- const createSourceDirCandidates = (candidates) => {
196
- const normalizedCandidates = candidates.map((candidate) => normalizePath$2(candidate));
197
- const sourceCandidates = normalizedCandidates.map(
198
- (candidate) => normalizePath$2(node_path.join("src", candidate))
199
- );
200
- return [.../* @__PURE__ */ new Set([...sourceCandidates, ...normalizedCandidates])];
201
- };
202
- const resolveSourceDir = (projectDir, candidates, fallback) => {
203
- for (const candidate of candidates) {
204
- if (node_fs.existsSync(node_path.join(projectDir, candidate))) {
205
- return candidate;
206
- }
207
- }
208
- return normalizePath$2(fallback);
209
- };
210
- const getPageSourceExtensionPriority = (filePath) => {
211
- const extension = node_path.extname(filePath).toLowerCase();
212
- const index = PAGE_SOURCE_EXTENSIONS.indexOf(
213
- extension
214
- );
215
- return index === -1 ? Number.MAX_SAFE_INTEGER : index;
216
- };
217
- const outputPathToSourceCandidates = (pageSourceRootDir, relativeOutputHtmlFilePath) => {
218
- const sourceStem = normalizePath$2(relativeOutputHtmlFilePath).replace(
219
- /\.html$/i,
220
- ""
221
- );
222
- return PAGE_SOURCE_EXTENSIONS.map(
223
- (extension) => node_path.join(pageSourceRootDir, `${sourceStem}${extension}`)
224
- );
225
- };
226
- const resolveSsgPaths = (projectDir, config) => {
227
- const pagesSourceDirCandidates = isDefaultPath(config.pages, DEFAULT_PAGES_DIR) ? createSourceDirCandidates([DEFAULT_PAGES_DIR]) : [normalizePath$2(config.pages)];
228
- const componentsSourceDirCandidates = isDefaultPath(
229
- config.components,
230
- DEFAULT_COMPONENTS_DIR
231
- ) ? createSourceDirCandidates(COMPONENTS_SOURCE_ALIASES) : [normalizePath$2(config.components)];
232
- const assetsSourceDirCandidates = isDefaultPath(config.assets, DEFAULT_ASSETS_DIR) ? createSourceDirCandidates([DEFAULT_ASSETS_DIR]) : [normalizePath$2(config.assets)];
233
- const pagesSourceDir = resolveSourceDir(
234
- projectDir,
235
- pagesSourceDirCandidates,
236
- pagesSourceDirCandidates[0] ?? DEFAULT_PAGES_DIR
237
- );
238
- const componentsSourceDir = resolveSourceDir(
239
- projectDir,
240
- componentsSourceDirCandidates,
241
- componentsSourceDirCandidates[0] ?? DEFAULT_COMPONENTS_DIR
242
- );
243
- const assetsSourceDir = resolveSourceDir(
244
- projectDir,
245
- assetsSourceDirCandidates,
246
- assetsSourceDirCandidates[0] ?? DEFAULT_ASSETS_DIR
247
- );
248
- const pagesSourceDirAbsolute = node_path.join(projectDir, pagesSourceDir);
249
- const componentsSourceDirAbsolute = node_path.join(projectDir, componentsSourceDir);
250
- const assetsSourceDirAbsolute = node_path.join(projectDir, assetsSourceDir);
251
- return {
252
- pagesSourceDir,
253
- pagesSourceDirAbsolute,
254
- pagesSourceDirCandidates,
255
- hasPagesSourceDir: node_fs.existsSync(pagesSourceDirAbsolute),
256
- componentsSourceDir,
257
- componentsSourceDirAbsolute,
258
- componentsSourceDirCandidates,
259
- hasComponentsSourceDir: node_fs.existsSync(componentsSourceDirAbsolute),
260
- componentsPublicDir: normalizePath$2(config.components),
261
- assetsSourceDir,
262
- assetsSourceDirAbsolute,
263
- assetsSourceDirCandidates,
264
- hasAssetsSourceDir: node_fs.existsSync(assetsSourceDirAbsolute),
265
- assetsPublicDir: normalizePath$2(config.assets)
266
- };
267
- };
268
- const getPageSourceRootDir = (projectDir, paths) => paths.hasPagesSourceDir ? paths.pagesSourceDirAbsolute : projectDir;
269
- const pageSourceFileToOutputPath = (pageSourceFile, pageSourceRootDir) => {
270
- const relativePagePath = node_path.relative(pageSourceRootDir, pageSourceFile).replace(
271
- /\\/g,
272
- "/"
273
- );
274
- return relativePagePath.replace(/\.(mdx|md)$/i, ".html");
275
- };
276
- const resolvePreferredPageSourceForOutputPath = (relativeOutputHtmlFilePath, pageSourceRootDir) => {
277
- for (const candidate of outputPathToSourceCandidates(
278
- pageSourceRootDir,
279
- relativeOutputHtmlFilePath
280
- )) {
281
- if (node_fs.existsSync(candidate)) {
282
- return candidate;
283
- }
284
- }
285
- return null;
286
- };
287
- const selectPreferredPageSourceFiles = (pageSourceFiles, pageSourceRootDir) => {
288
- const selectedFiles = /* @__PURE__ */ new Map();
289
- const sortedSourceFiles = [...pageSourceFiles].sort((left, right) => {
290
- const leftOutputPath = pageSourceFileToOutputPath(left, pageSourceRootDir);
291
- const rightOutputPath = pageSourceFileToOutputPath(right, pageSourceRootDir);
292
- const outputPathCompare = leftOutputPath.localeCompare(rightOutputPath);
293
- if (outputPathCompare !== 0) {
294
- return outputPathCompare;
295
- }
296
- return getPageSourceExtensionPriority(left) - getPageSourceExtensionPriority(right);
297
- });
298
- for (const pageSourceFile of sortedSourceFiles) {
299
- const outputPath = pageSourceFileToOutputPath(
300
- pageSourceFile,
301
- pageSourceRootDir
302
- );
303
- if (!selectedFiles.has(outputPath)) {
304
- selectedFiles.set(outputPath, pageSourceFile);
305
- }
306
- }
307
- return [...selectedFiles.values()];
308
- };
309
- const resolvePageSourceFileForPath = (pathname, pageSourceRootDir, hasPagesSourceDir) => {
310
- const outputCandidates = pathname === "/" ? ["index.html"] : (() => {
311
- const trimmedPath = pathname.replace(/^\/+/, "").replace(/\/+$/, "");
312
- if (trimmedPath.length === 0) {
313
- return ["index.html"];
314
- }
315
- if (node_path.extname(trimmedPath)) {
316
- return [trimmedPath];
317
- }
318
- return [`${trimmedPath}.html`, `${trimmedPath}/index.html`];
319
- })();
320
- if (!hasPagesSourceDir) {
321
- return outputCandidates.includes("index.html") ? resolvePreferredPageSourceForOutputPath("index.html", pageSourceRootDir) : null;
322
- }
323
- for (const outputCandidate of outputCandidates) {
324
- const sourceFile = resolvePreferredPageSourceForOutputPath(
325
- outputCandidate,
326
- pageSourceRootDir
327
- );
328
- if (sourceFile) {
329
- return sourceFile;
330
- }
331
- }
332
- return null;
333
- };
334
- const filePathToRoute = (filePath, config, cwd) => {
335
- const paths = resolveSsgPaths(cwd, config);
336
- const pageSourceRootDir = paths.hasPagesSourceDir && normalizePath$2(filePath).startsWith(
337
- `${normalizePath$2(paths.pagesSourceDirAbsolute)}/`
338
- ) ? paths.pagesSourceDirAbsolute : cwd;
339
- let routePath = pageSourceFileToOutputPath(filePath, pageSourceRootDir);
340
- routePath = normalizePath$2(routePath);
341
- if (routePath === "index.html") {
342
- return "/";
343
- }
344
- if (routePath.endsWith("/index.html")) {
345
- routePath = routePath.slice(0, -"/index.html".length);
346
- } else {
347
- routePath = routePath.replace(/\.html$/i, "");
348
- }
349
- if (!routePath.startsWith("/")) {
350
- routePath = `/${routePath}`;
351
- }
352
- return routePath;
353
- };
354
-
355
287
  const validateProjectDir = (projectDir) => {
356
288
  try {
357
289
  if (!node_fs.statSync(projectDir).isDirectory()) {
@@ -421,25 +353,40 @@ const discoverEndpointSourceFiles = async (pagesDir) => {
421
353
  };
422
354
  const compileEndpoints = async (sourceFiles, pagesDir, outDir, debug = false) => {
423
355
  if (sourceFiles.length === 0) return /* @__PURE__ */ new Map();
356
+ const resolvedPagesDir = node_path.resolve(pagesDir);
357
+ const resolvedOutDir = node_path.resolve(outDir);
424
358
  if (debug) {
425
359
  console.log(`Compiling ${sourceFiles.length} endpoint source file(s)...`);
426
360
  }
427
- console.time("[endpoints] esbuild-compile");
428
- await esbuild.build({
429
- entryPoints: sourceFiles,
430
- format: "esm",
431
- bundle: true,
432
- platform: "node",
433
- target: ["esnext"],
434
- outdir: outDir,
435
- outbase: pagesDir,
436
- outExtension: { ".js": ".mjs" }
437
- });
438
- console.timeEnd("[endpoints] esbuild-compile");
439
361
  const mapping = /* @__PURE__ */ new Map();
440
- for (const src of sourceFiles) {
441
- const rel = node_path.relative(pagesDir, src).replace(/\.(ts|js)$/, ".mjs");
442
- mapping.set(src, node_path.join(outDir, rel));
362
+ console.time("[endpoints] rolldown-compile");
363
+ try {
364
+ for (const src of sourceFiles) {
365
+ const resolvedSourceFile = node_path.resolve(src);
366
+ const rel = node_path.relative(resolvedPagesDir, resolvedSourceFile).replace(
367
+ /\.(ts|js)$/,
368
+ ".mjs"
369
+ );
370
+ const compiledFile = node_path.join(resolvedOutDir, rel);
371
+ const compiledDir = node_path.dirname(compiledFile);
372
+ if (!node_fs.existsSync(compiledDir)) {
373
+ node_fs.mkdirSync(compiledDir, { recursive: true });
374
+ }
375
+ await rolldown.build({
376
+ input: resolvedSourceFile,
377
+ cwd: resolvedPagesDir,
378
+ platform: "node",
379
+ output: {
380
+ file: compiledFile,
381
+ format: "esm",
382
+ codeSplitting: false,
383
+ sourcemap: false
384
+ }
385
+ });
386
+ mapping.set(src, compiledFile);
387
+ }
388
+ } finally {
389
+ console.timeEnd("[endpoints] rolldown-compile");
443
390
  }
444
391
  return mapping;
445
392
  };
@@ -490,7 +437,7 @@ const resolveEndpoints = async (pagesDir, endpointsDir, debug = false) => {
490
437
  return endpoints;
491
438
  };
492
439
  const buildEndpoints = async (projectDir, config, debug = false) => {
493
- const pagesDir = resolveSsgPaths(projectDir, config).pagesSourceDirAbsolute;
440
+ const pagesDir = path.resolveSsgPaths(projectDir, config).pagesSourceDirAbsolute;
494
441
  const outputDir = node_path.join(projectDir, config.output);
495
442
  const endpointsDir = node_path.join(projectDir, ".endpoints");
496
443
  const endpoints = await resolveEndpoints(pagesDir, endpointsDir, debug);
@@ -655,7 +602,7 @@ const registerEndpoints = async (registrar, projectDir, _config, debug = false)
655
602
  }
656
603
  };
657
604
 
658
- const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite-CkpguLfK.cjs', document.baseURI).href)));
605
+ const __filename$1 = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite-BC7XxFTV.cjs', document.baseURI).href)));
659
606
  const __dirname$1 = node_path.dirname(__filename$1);
660
607
  const isHtmlLikePageSource = (filePath) => {
661
608
  const extension = node_path.extname(filePath).toLowerCase();
@@ -682,7 +629,7 @@ const resolveLocalHelperFile = (sourceRelativePath, builtRelativePath) => {
682
629
  return node_path.resolve(__dirname$1, builtRelativePath);
683
630
  };
684
631
  const loadProjectTailwindVitePlugins = async (projectDir, debug) => {
685
- const requireFromBuild = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite-CkpguLfK.cjs', document.baseURI).href)));
632
+ const requireFromBuild = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite-BC7XxFTV.cjs', document.baseURI).href)));
686
633
  try {
687
634
  const resolvedPluginPath = requireFromBuild.resolve("@tailwindcss/vite", {
688
635
  paths: [projectDir]
@@ -795,7 +742,7 @@ const build = async ({
795
742
  timeDebug("[build] readConfig");
796
743
  const config = await readConfig(projectDir, debug);
797
744
  timeEndDebug("[build] readConfig");
798
- const projectPaths = resolveSsgPaths(projectDir, config);
745
+ const projectPaths = path.resolveSsgPaths(projectDir, config);
799
746
  if (debug) {
800
747
  console.log("Using config:", config);
801
748
  }
@@ -806,7 +753,7 @@ const build = async ({
806
753
  const hasInputPagesDir = projectPaths.hasPagesSourceDir;
807
754
  const tmpPagesDir = node_path.join(config.tmp, projectPaths.pagesSourceDir);
808
755
  const tmpComponentsDir = node_path.join(config.tmp, projectPaths.componentsSourceDir);
809
- const tmpPageSourceRootDir = hasInputPagesDir ? tmpPagesDir : getPageSourceRootDir(config.tmp, resolveSsgPaths(config.tmp, config));
756
+ const tmpPageSourceRootDir = hasInputPagesDir ? tmpPagesDir : path.getPageSourceRootDir(config.tmp, path.resolveSsgPaths(config.tmp, config));
810
757
  const outputProjectDir = node_path.join(projectDir, config.output);
811
758
  const outputPagesDir = outputProjectDir;
812
759
  const outputComponentsDir = node_path.join(
@@ -935,17 +882,17 @@ const build = async ({
935
882
  timeDebug("[build] collect-pages");
936
883
  if (changeKind === "page") {
937
884
  const changedPageSourceFile = node_path.join(config.tmp, changedRelative);
938
- const changedOutputPath = pageSourceFileToOutputPath(
885
+ const changedOutputPath = path.pageSourceFileToOutputPath(
939
886
  changedPageSourceFile,
940
887
  tmpPageSourceRootDir
941
888
  );
942
- const preferredPageSourceFile = resolvePreferredPageSourceForOutputPath(
889
+ const preferredPageSourceFile = path.resolvePreferredPageSourceForOutputPath(
943
890
  changedOutputPath,
944
891
  tmpPageSourceRootDir
945
892
  );
946
893
  pageSourceFiles = preferredPageSourceFile ? [preferredPageSourceFile] : [];
947
894
  } else if (hasInputPagesDir) {
948
- pageSourceFiles = selectPreferredPageSourceFiles(
895
+ pageSourceFiles = path.selectPreferredPageSourceFiles(
949
896
  await glob.async([
950
897
  node_path.join(tmpPagesDir, "**/*.md"),
951
898
  node_path.join(tmpPagesDir, "**/*.mdx"),
@@ -954,7 +901,7 @@ const build = async ({
954
901
  tmpPageSourceRootDir
955
902
  );
956
903
  } else {
957
- const preferredRootIndexFile = resolvePreferredPageSourceForOutputPath(
904
+ const preferredRootIndexFile = path.resolvePreferredPageSourceForOutputPath(
958
905
  "index.html",
959
906
  tmpPageSourceRootDir
960
907
  );
@@ -964,24 +911,33 @@ const build = async ({
964
911
  }
965
912
  if (changeKind !== "asset" && changeKind !== "endpoint") {
966
913
  timeDebug("[build] render-pages");
967
- const pageModuleServer = await vite.createServer({
968
- root: config.tmp,
969
- configFile: false,
970
- appType: "custom",
971
- logLevel: debug ? "info" : "error",
972
- server: {
973
- middlewareMode: true
974
- },
975
- plugins: [
976
- defuss({ enableJsxDevMode: true }),
977
- mdx({
978
- jsxImportSource: "defuss",
979
- development: true,
980
- remarkPlugins: config.remarkPlugins,
981
- rehypePlugins: config.rehypePlugins
982
- })
983
- ]
984
- });
914
+ const pageModuleServer = await vite.createServer(
915
+ vite.mergeConfig(
916
+ {
917
+ root: config.tmp,
918
+ configFile: false,
919
+ appType: "custom",
920
+ logLevel: debug ? "info" : "error",
921
+ server: {
922
+ middlewareMode: true
923
+ },
924
+ plugins: [
925
+ createContentModulePlugin({
926
+ projectDir,
927
+ pagesDir: config.pages
928
+ }),
929
+ defuss({ enableJsxDevMode: true }),
930
+ mdx({
931
+ jsxImportSource: "defuss",
932
+ development: true,
933
+ remarkPlugins: config.remarkPlugins,
934
+ rehypePlugins: config.rehypePlugins
935
+ })
936
+ ]
937
+ },
938
+ config.viteConfig ?? {}
939
+ )
940
+ );
985
941
  try {
986
942
  let inputFiles;
987
943
  if (changeKind === "page") {
@@ -998,7 +954,7 @@ const build = async ({
998
954
  node_fs.mkdirSync(outputProjectDir, { recursive: true });
999
955
  }
1000
956
  for (const inputFile of inputFiles) {
1001
- const relativeOutputHtmlFilePath = pageSourceFileToOutputPath(
957
+ const relativeOutputHtmlFilePath = path.pageSourceFileToOutputPath(
1002
958
  inputFile,
1003
959
  tmpPageSourceRootDir
1004
960
  );
@@ -1122,28 +1078,33 @@ const build = async ({
1122
1078
  defuss(),
1123
1079
  ...await loadProjectTailwindVitePlugins(projectDir, debug)
1124
1080
  ];
1125
- await vite.build({
1126
- root: node_path.resolve(tmpComponentsDir),
1127
- configFile: false,
1128
- publicDir: false,
1129
- plugins: componentBuildPlugins,
1130
- build: {
1131
- lib: {
1132
- entry: componentEntries,
1133
- formats: ["es"],
1134
- fileName: (_format, entryName) => `${entryName}.js`
1135
- },
1136
- target: "esnext",
1137
- outDir: node_path.resolve(tmpComponentOutDir),
1138
- emptyOutDir: false,
1139
- minify: false,
1140
- rollupOptions: {
1141
- output: {
1142
- chunkFileNames: "chunks/[name]-[hash].js"
1081
+ await vite.build(
1082
+ vite.mergeConfig(
1083
+ {
1084
+ root: node_path.resolve(tmpComponentsDir),
1085
+ configFile: false,
1086
+ publicDir: false,
1087
+ plugins: componentBuildPlugins,
1088
+ build: {
1089
+ lib: {
1090
+ entry: componentEntries,
1091
+ formats: ["es"],
1092
+ fileName: (_format, entryName) => `${entryName}.js`
1093
+ },
1094
+ target: "esnext",
1095
+ outDir: node_path.resolve(tmpComponentOutDir),
1096
+ emptyOutDir: false,
1097
+ minify: false,
1098
+ rollupOptions: {
1099
+ output: {
1100
+ chunkFileNames: "chunks/[name]-[hash].js"
1101
+ }
1102
+ }
1143
1103
  }
1144
- }
1145
- }
1146
- });
1104
+ },
1105
+ config.viteConfig ?? {}
1106
+ )
1107
+ );
1147
1108
  await normalizeComponentStylesheets(tmpComponentOutDir);
1148
1109
  timeEndDebug("[build] vite-components");
1149
1110
  }
@@ -1266,26 +1227,33 @@ const discoverRpcFile = (projectDir) => {
1266
1227
  return null;
1267
1228
  };
1268
1229
  const compileRpcModule = async (rpcFilePath, projectDir, debug = false) => {
1269
- const outDir = node_path.join(projectDir, ".rpc");
1230
+ const resolvedProjectDir = node_path.resolve(projectDir);
1231
+ const resolvedRpcFilePath = node_path.resolve(rpcFilePath);
1232
+ const outDir = node_path.join(resolvedProjectDir, ".rpc");
1233
+ const tsconfigPath = node_path.join(resolvedProjectDir, "tsconfig.json");
1270
1234
  if (!node_fs.existsSync(outDir)) {
1271
1235
  node_fs.mkdirSync(outDir, { recursive: true });
1272
1236
  }
1273
1237
  if (debug) {
1274
- console.log(`Compiling RPC module: ${rpcFilePath}`);
1238
+ console.log(`Compiling RPC module: ${resolvedRpcFilePath}`);
1275
1239
  }
1276
- const compileLabel = "[rpc] esbuild-compile";
1240
+ const compileLabel = "[rpc] rolldown-compile";
1277
1241
  console.time(compileLabel);
1278
1242
  try {
1279
- await esbuild.build({
1280
- entryPoints: [rpcFilePath],
1281
- format: "esm",
1282
- bundle: true,
1243
+ await rolldown.build({
1244
+ input: resolvedRpcFilePath,
1245
+ cwd: resolvedProjectDir,
1283
1246
  platform: "node",
1284
- target: ["esnext"],
1285
- outdir: outDir,
1286
- outExtension: { ".js": ".mjs" },
1287
- // Mark defuss-rpc as external so it uses the installed version
1288
- external: ["defuss-rpc", "defuss-rpc/*"]
1247
+ tsconfig: node_fs.existsSync(tsconfigPath) ? tsconfigPath : false,
1248
+ // Mark defuss-rpc as external so it uses the installed version.
1249
+ external: ["defuss-rpc", /^defuss-rpc(?:\/.*)?$/],
1250
+ output: {
1251
+ dir: outDir,
1252
+ format: "esm",
1253
+ entryFileNames: "rpc.mjs",
1254
+ chunkFileNames: "chunks/[name]-[hash].mjs",
1255
+ sourcemap: false
1256
+ }
1289
1257
  });
1290
1258
  } finally {
1291
1259
  console.timeEnd(compileLabel);
@@ -1297,13 +1265,12 @@ const compileRpcModule = async (rpcFilePath, projectDir, debug = false) => {
1297
1265
  return compiledPath;
1298
1266
  };
1299
1267
  const loadRpcModule = async (compiledPath) => {
1300
- const code = await promises.readFile(compiledPath, "utf-8");
1301
- const tmpFile = node_path.join(
1302
- node_os.tmpdir(),
1303
- `defuss-rpc-${Date.now()}-${Math.random().toString(36).slice(2)}.mjs`
1268
+ const compiledUrl = node_url.pathToFileURL(compiledPath);
1269
+ compiledUrl.searchParams.set(
1270
+ "t",
1271
+ `${Date.now()}-${Math.random().toString(36).slice(2)}`
1304
1272
  );
1305
- await promises.writeFile(tmpFile, code, "utf-8");
1306
- return await import(tmpFile);
1273
+ return await import(compiledUrl.href);
1307
1274
  };
1308
1275
  const buildRpcNamespace = (moduleExports) => {
1309
1276
  const namespace = {};
@@ -1356,6 +1323,7 @@ const initializeRpc = async (projectDir, config, debug = false) => {
1356
1323
  }
1357
1324
  try {
1358
1325
  const compiledPath = await compileRpcModule(rpcFilePath, projectDir, debug);
1326
+ await rpcServer.clearRpcServer();
1359
1327
  const moduleExports = await loadRpcModule(compiledPath);
1360
1328
  const namespace = buildRpcNamespace(moduleExports);
1361
1329
  if (Object.keys(namespace).length === 0) {
@@ -1364,7 +1332,6 @@ const initializeRpc = async (projectDir, config, debug = false) => {
1364
1332
  );
1365
1333
  return false;
1366
1334
  }
1367
- rpcServer.clearRpcServer();
1368
1335
  rpcServer.createRpcServer(namespace);
1369
1336
  console.log(
1370
1337
  `RPC initialized with ${Object.keys(namespace).length} namespace(s): ${Object.keys(namespace).join(", ")}`
@@ -1841,7 +1808,7 @@ const getOutputCandidates = (pathname) => {
1841
1808
  return [`${trimmedPath}.html`, `${trimmedPath}/index.html`];
1842
1809
  };
1843
1810
  const classifyChangedFile = (file, projectDir, config, rpcFile) => {
1844
- const paths = resolveSsgPaths(projectDir, config);
1811
+ const paths = path.resolveSsgPaths(projectDir, config);
1845
1812
  const relativeFile = node_path.relative(projectDir, file).replace(/^[\\/]+/, "").replace(/\\/g, "/");
1846
1813
  if (relativeFile.startsWith("..")) {
1847
1814
  return "other";
@@ -1880,7 +1847,7 @@ const filePathToComponentPublicPath = (file, componentsSourceDir, componentsPubl
1880
1847
  return `/${node_path.join(componentsPublicDir, relativeComponentPath).replace(/\\/g, "/").replace(/\.t?sx?$/, ".js")}`;
1881
1848
  };
1882
1849
  const refreshDynamicEndpoints = async (projectDir, config, debug) => {
1883
- const pagesDir = resolveSsgPaths(projectDir, config).pagesSourceDirAbsolute;
1850
+ const pagesDir = path.resolveSsgPaths(projectDir, config).pagesSourceDirAbsolute;
1884
1851
  const endpointsDir = node_path.join(projectDir, ".endpoints");
1885
1852
  return (await resolveEndpoints(pagesDir, endpointsDir, debug)).filter(
1886
1853
  (endpoint) => !endpoint.prerender
@@ -1934,7 +1901,7 @@ function defussSsg(options = {}) {
1934
1901
  };
1935
1902
  const refreshConfig = async () => {
1936
1903
  config = await readConfig(projectDir, debug);
1937
- paths = resolveSsgPaths(projectDir, config);
1904
+ paths = path.resolveSsgPaths(projectDir, config);
1938
1905
  rpcFile = typeof config.rpc === "string" ? node_path.resolve(projectDir, config.rpc) : discoverRpcFile(projectDir);
1939
1906
  };
1940
1907
  const enqueue = (task) => {
@@ -1997,9 +1964,9 @@ function defussSsg(options = {}) {
1997
1964
  }, 40);
1998
1965
  return pendingRpcReload.promise;
1999
1966
  };
2000
- const scheduleSsgReload = (server, file, kind) => {
1967
+ const scheduleSsgReload = (server, file, kind, reloadCurrentPage = false) => {
2001
1968
  const absoluteFile = node_path.resolve(file);
2002
- const reloadKey = `${kind}:${absoluteFile}`;
1969
+ const reloadKey = `${kind}:${absoluteFile}:${reloadCurrentPage ? "current" : "target"}`;
2003
1970
  const existingTimer = ssgReloadTimers.get(reloadKey);
2004
1971
  if (existingTimer) {
2005
1972
  clearTimeout(existingTimer);
@@ -2033,9 +2000,9 @@ function defussSsg(options = {}) {
2033
2000
  }
2034
2001
  lastSsgReloadSignatures.set(reloadKey, reloadSignature);
2035
2002
  }).then(() => {
2036
- const currentPaths = resolveSsgPaths(projectDir, config);
2003
+ const currentPaths = path.resolveSsgPaths(projectDir, config);
2037
2004
  sendCustomEvent(server, "defuss:ssg-reload", {
2038
- path: kind === "page" && isHtmlLikeFile(absoluteFile) ? filePathToRoute(absoluteFile, config, projectDir) : void 0,
2005
+ path: !reloadCurrentPage && kind === "page" && isHtmlLikeFile(absoluteFile) ? path.filePathToRoute(absoluteFile, config, projectDir) : void 0,
2039
2006
  kind,
2040
2007
  componentSrc: kind === "component" ? filePathToComponentPublicPath(
2041
2008
  absoluteFile,
@@ -2161,10 +2128,9 @@ function defussSsg(options = {}) {
2161
2128
  };
2162
2129
  const maybeHandleRpcRequest = async (req, res) => {
2163
2130
  const requestUrl = new URL(req.url || "/", "http://localhost");
2164
- if (req.method !== "POST") {
2165
- return false;
2166
- }
2167
- if (requestUrl.pathname !== "/rpc" && requestUrl.pathname !== "/rpc/schema") {
2131
+ const pathname = requestUrl.pathname;
2132
+ const isRpcRequest = pathname === "/rpc" || pathname === "/rpc/schema" || pathname === "/rpc/upload" || pathname.startsWith("/rpc/upload/");
2133
+ if (!isRpcRequest) {
2168
2134
  return false;
2169
2135
  }
2170
2136
  if (!rpcFile || config.rpc === false) {
@@ -2208,10 +2174,10 @@ function defussSsg(options = {}) {
2208
2174
  return false;
2209
2175
  };
2210
2176
  const resolveSourceFileForPath = async (pathname) => {
2211
- const currentPaths = resolveSsgPaths(projectDir, config);
2212
- return resolvePageSourceFileForPath(
2177
+ const currentPaths = path.resolveSsgPaths(projectDir, config);
2178
+ return path.resolvePageSourceFileForPath(
2213
2179
  pathname,
2214
- getPageSourceRootDir(projectDir, currentPaths),
2180
+ path.getPageSourceRootDir(projectDir, currentPaths),
2215
2181
  currentPaths.hasPagesSourceDir
2216
2182
  );
2217
2183
  };
@@ -2242,10 +2208,10 @@ function defussSsg(options = {}) {
2242
2208
  const browserGlobals = server.getBrowserGlobals();
2243
2209
  const document = server.getDocument(false, browserGlobals);
2244
2210
  let vdom = PageComponent();
2245
- const currentPaths = resolveSsgPaths(projectDir, config);
2246
- const relativeOutputHtmlFilePath = pageSourceFileToOutputPath(
2211
+ const currentPaths = path.resolveSsgPaths(projectDir, config);
2212
+ const relativeOutputHtmlFilePath = path.pageSourceFileToOutputPath(
2247
2213
  sourceFile,
2248
- getPageSourceRootDir(projectDir, currentPaths)
2214
+ path.getPageSourceRootDir(projectDir, currentPaths)
2249
2215
  );
2250
2216
  vdom = applyAutoHydrate(
2251
2217
  vdom,
@@ -2276,31 +2242,42 @@ function defussSsg(options = {}) {
2276
2242
  const maybeServeComponent = async (server, req, res) => {
2277
2243
  const requestUrl = new URL(req.url || "/", "http://localhost");
2278
2244
  const pathname = requestUrl.pathname;
2279
- const currentPaths = resolveSsgPaths(projectDir, config);
2245
+ const currentPaths = path.resolveSsgPaths(projectDir, config);
2280
2246
  const componentRoutePrefix = `/${currentPaths.componentsPublicDir}/`;
2281
2247
  if (!pathname.startsWith(componentRoutePrefix)) {
2282
2248
  return false;
2283
2249
  }
2284
2250
  const relativeComponentPath = pathname.slice(componentRoutePrefix.length);
2285
2251
  const componentExtension = node_path.extname(relativeComponentPath).toLowerCase();
2286
- const isBuiltComponentAsset = relativeComponentPath === "runtime.js" || relativeComponentPath.startsWith("chunks/") || /^chunk-|^client-/.test(relativeComponentPath) || componentExtension !== ".js";
2252
+ const sourceExtensions = /* @__PURE__ */ new Set([".tsx", ".ts", ".jsx", ".js"]);
2253
+ const isBuiltComponentAsset = relativeComponentPath === "runtime.js" || relativeComponentPath.startsWith("chunks/") || /^chunk-|^client-/.test(relativeComponentPath) || !sourceExtensions.has(componentExtension);
2287
2254
  if (isBuiltComponentAsset) {
2288
2255
  return false;
2289
2256
  }
2290
- const componentBase = relativeComponentPath.replace(
2291
- node_path.extname(relativeComponentPath),
2292
- ""
2293
- );
2294
- const extensions = [".tsx", ".ts", ".jsx", ".js"];
2295
2257
  let sourceFile = null;
2296
- for (const ext of extensions) {
2297
- const candidate = node_path.join(
2258
+ if (componentExtension !== ".js") {
2259
+ const directSourceCandidate = node_path.join(
2298
2260
  currentPaths.componentsSourceDirAbsolute,
2299
- `${componentBase}${ext}`
2261
+ relativeComponentPath
2300
2262
  );
2301
- if (node_fs.existsSync(candidate)) {
2302
- sourceFile = candidate;
2303
- break;
2263
+ if (node_fs.existsSync(directSourceCandidate)) {
2264
+ sourceFile = directSourceCandidate;
2265
+ }
2266
+ }
2267
+ if (!sourceFile) {
2268
+ const componentBase = relativeComponentPath.replace(
2269
+ node_path.extname(relativeComponentPath),
2270
+ ""
2271
+ );
2272
+ for (const ext of sourceExtensions) {
2273
+ const candidate = node_path.join(
2274
+ currentPaths.componentsSourceDirAbsolute,
2275
+ `${componentBase}${ext}`
2276
+ );
2277
+ if (node_fs.existsSync(candidate)) {
2278
+ sourceFile = candidate;
2279
+ break;
2280
+ }
2304
2281
  }
2305
2282
  }
2306
2283
  if (!sourceFile) {
@@ -2342,7 +2319,7 @@ function defussSsg(options = {}) {
2342
2319
  MIME_TYPES[node_path.extname(outputFile)] ?? "application/octet-stream"
2343
2320
  );
2344
2321
  if (outputFile.endsWith(".html")) {
2345
- const currentPaths = resolveSsgPaths(projectDir, config);
2322
+ const currentPaths = path.resolveSsgPaths(projectDir, config);
2346
2323
  const html = await server.transformIndexHtml(
2347
2324
  requestUrl.pathname,
2348
2325
  injectHmrClientModule(
@@ -2446,7 +2423,17 @@ function defussSsg(options = {}) {
2446
2423
  await scheduleEndpointReload(server, file);
2447
2424
  return;
2448
2425
  }
2449
- if (kind === "page" || kind === "component" || kind === "dependency") {
2426
+ if (kind === "page") {
2427
+ invalidateContentModule(server, Date.now());
2428
+ await scheduleSsgReload(
2429
+ server,
2430
+ file,
2431
+ kind,
2432
+ hasContentModuleImporters(server)
2433
+ );
2434
+ return;
2435
+ }
2436
+ if (kind === "component" || kind === "dependency") {
2450
2437
  await scheduleSsgReload(server, file, kind);
2451
2438
  return;
2452
2439
  }
@@ -2502,7 +2489,21 @@ function defussSsg(options = {}) {
2502
2489
  await scheduleEndpointReload(ctx.server, ctx.file);
2503
2490
  return [];
2504
2491
  }
2505
- if (kind === "page" || kind === "component" || kind === "dependency") {
2492
+ if (kind === "page") {
2493
+ if (ctx.type === "update") {
2494
+ await ctx.read();
2495
+ }
2496
+ invalidateChangedFile(ctx.server, ctx.file, ctx.timestamp);
2497
+ invalidateContentModule(ctx.server, ctx.timestamp);
2498
+ await scheduleSsgReload(
2499
+ ctx.server,
2500
+ ctx.file,
2501
+ kind,
2502
+ hasContentModuleImporters(ctx.server)
2503
+ );
2504
+ return [];
2505
+ }
2506
+ if (kind === "component" || kind === "dependency") {
2506
2507
  if (ctx.type === "update") {
2507
2508
  await ctx.read();
2508
2509
  }
@@ -2521,7 +2522,13 @@ function defussSsg(options = {}) {
2521
2522
  return [];
2522
2523
  }
2523
2524
  };
2524
- return [plugin];
2525
+ return [
2526
+ createContentModulePlugin({
2527
+ projectDir: () => projectDir,
2528
+ pagesDir: () => config.pages
2529
+ }),
2530
+ plugin
2531
+ ];
2525
2532
  }
2526
2533
 
2527
2534
  exports.HTTP_METHODS = HTTP_METHODS;