@monkeyplus/flow 5.0.0-rc.8 → 5.0.0-rc.81

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.
@@ -1,6 +1,6 @@
1
1
  import type { RadixRouter } from 'radix3';
2
2
  import type { Hookable } from 'hookable';
3
- import type { FlowPage, RuntimeConfig } from '@monkeyplus/flow-schema';
3
+ import type { FlowAppUtils, FlowPage, RuntimeConfig } from '@monkeyplus/flow-schema';
4
4
  declare type HookResult = Promise<void> | void;
5
5
  export interface FlowAppHooks {
6
6
  'flow:pages': (page: FlowPage[]) => HookResult;
@@ -11,6 +11,10 @@ export interface FlowAppHooks {
11
11
  bodyStart: string[];
12
12
  }) => HookResult;
13
13
  'page:links': (links: string[]) => HookResult;
14
+ 'page:context': (ctx: {
15
+ page: string;
16
+ localeCode: string;
17
+ }, utils: any, data: Record<string, any>) => HookResult;
14
18
  'page:chunks': (bundle: string, scripts: {
15
19
  head: string[];
16
20
  body: string[];
@@ -27,11 +31,14 @@ export interface FlowApp {
27
31
  callHook: FlowApp['hooks']['callHook'];
28
32
  eta: any;
29
33
  app: {
30
- utils: Record<string, any>;
34
+ utils: FlowAppUtils;
31
35
  plugins: Record<string, any>;
32
36
  globals: Record<string, any>;
33
37
  };
34
38
  engine: string;
39
+ site: {
40
+ origin: string;
41
+ };
35
42
  engines: Record<string, (template: string) => string>;
36
43
  generate: boolean;
37
44
  render: (view: Record<string, string>, data: any) => Promise<string> | void | string;
package/dist/app/flow.mjs CHANGED
@@ -20,6 +20,9 @@ export function createFlowApp({ runtimeConfig }) {
20
20
  },
21
21
  engine: "eta",
22
22
  engines: {},
23
+ site: {
24
+ origin: `${process.env.URL || "http://localhost"}`
25
+ },
23
26
  generate: runtimeConfig.generate
24
27
  };
25
28
  flowApp.engines.eta = (template) => {
@@ -1,6 +1,6 @@
1
- import { defineEventHandler } from "h3";
2
1
  import "node-fetch-native/polyfill";
3
- import { useRuntimeConfig } from "#internal/nitro";
2
+ import { defineEventHandler } from "h3";
3
+ import { defineCachedFunction, useRuntimeConfig } from "#internal/nitro";
4
4
  const getServerApp = cachedImport(() => import("#server"));
5
5
  const getFlowRenderer = cachedResult(async () => {
6
6
  const createFlowApp = await getServerApp();
@@ -12,6 +12,7 @@ export default defineEventHandler(async ({ context }) => {
12
12
  const flow = await getFlowRenderer();
13
13
  context.flow = flow;
14
14
  context.render = flow.render;
15
+ context.defineCachedFunction = defineCachedFunction;
15
16
  });
16
17
  function _interopDefault(e) {
17
18
  return e && typeof e === "object" && "default" in e ? e.default : e;
@@ -1,4 +1,10 @@
1
1
  import { eventHandler, useQuery } from "h3";
2
+ import { joinURL } from "ufo";
3
+ const normalizeCall = async (seo, ctx) => {
4
+ if (typeof seo === "function")
5
+ return await seo(ctx);
6
+ return seo || {};
7
+ };
2
8
  export default eventHandler(async (event) => {
3
9
  const url = event.req.url?.split("?")[0];
4
10
  const flow = event.context.flow;
@@ -9,35 +15,58 @@ export default eventHandler(async (event) => {
9
15
  const scripts = { head: [], bodyStart: [], bodyEnd: [] };
10
16
  const chunks = { head: [], body: [] };
11
17
  const generate = {};
12
- const { page, locale, params, view } = flow.router.byUrl.lookup(url) || {};
18
+ const { page, locale, params, view, name: pageName } = flow.router.byUrl.lookup(url) || {};
13
19
  if (!page)
14
20
  return;
15
21
  await flow.callHook("page:scripts", scripts);
16
22
  if (view.bundle)
17
23
  await flow.callHook("page:chunks", view.bundle, chunks);
18
24
  const templateContext = {};
19
- const dynamyc = params?._;
20
- const contextPage = {};
25
+ const dynamic = params?._;
26
+ const contextPage = {
27
+ chunks,
28
+ locale
29
+ };
21
30
  const contextInject = {};
22
- const utils = Object.assign({ getLocale: () => locale, injectContext: (key, value) => contextInject[key] = value }, flow.app.utils);
31
+ const utils = Object.assign({ getLocale: () => locale, injectContext: (key, value) => contextInject[key] = value, defineCachedFunction: event.context.defineCachedFunction }, flow.app.utils);
32
+ const contextHooks = {};
33
+ await flow.callHook("page:context", { localeCode: locale.code, page: pageName }, utils, contextHooks);
23
34
  templateContext.url = url;
35
+ templateContext.baseURL = flow.$config.app.baseURL;
36
+ const pageObject = {
37
+ name: pageName,
38
+ pathname: url,
39
+ url: joinURL(flow.site.origin, templateContext.baseURL, `${url}`),
40
+ origin: flow.site.origin,
41
+ joinOrigin: (_url, includeBase) => joinURL(flow.site.origin, includeBase ? templateContext.baseURL : "/", _url)
42
+ };
43
+ templateContext.page = pageObject;
44
+ contextPage.page = pageObject;
24
45
  templateContext.locale = locale;
25
46
  templateContext.view = view;
26
- if (dynamyc && page.dynamic) {
47
+ if (dynamic && page.dynamic) {
27
48
  const pages = await page.dynamic.method({ locale, utils });
28
- const dynamicPage = pages.find((_page) => _page.url === dynamyc);
49
+ const dynamicPage = pages.find((_page) => _page.url === dynamic);
29
50
  if (!dynamicPage)
30
51
  return;
31
52
  if (page.dynamic.assign)
32
53
  templateContext[page.dynamic.assign] = dynamicPage.context;
33
- contextPage.dynamyc = dynamicPage;
54
+ contextPage.dynamic = dynamicPage;
34
55
  }
35
56
  templateContext.seo = {};
36
- templateContext.context = {};
37
- templateContext.sharedContext = {};
57
+ const sharedContext = await utils.getSharedContext({
58
+ ...contextHooks,
59
+ ...contextPage,
60
+ utils
61
+ });
62
+ templateContext.sharedContext = sharedContext || {};
38
63
  templateContext.utils = utils;
39
- templateContext.seo = await page.seo?.({ ...contextPage, utils }) || {};
40
- templateContext.context = await page.context?.({ ...contextPage, utils }) || {};
64
+ templateContext.seo = await normalizeCall(page?.seo, { ...contextHooks, ...contextPage, utils, sharedContext });
65
+ const contexData = await page.context?.({ ...contextHooks, ...contextPage, utils, sharedContext }) || {};
66
+ templateContext.context = {
67
+ ...contextHooks,
68
+ ...contexData
69
+ };
41
70
  templateContext.getHeadScripts = () => {
42
71
  return scripts.head.join("\n");
43
72
  };
@@ -53,8 +82,14 @@ export default eventHandler(async (event) => {
53
82
  const query = useQuery(event);
54
83
  if (query?.context)
55
84
  return { ...templateContext, utils: Object.keys(utils) };
56
- const html = await flow.render(view, templateContext);
57
- event.res.setHeader("Content-Type", "text/html;charset=UTF-8");
85
+ let html;
86
+ if (view.render)
87
+ html = await view.render(templateContext, event);
88
+ else
89
+ html = await flow.render(view, templateContext);
90
+ event.res.setHeader("Content-Type", view.contentType || "text/html;charset=UTF-8");
91
+ if (view.postRender)
92
+ html = await view.postRender(html, event);
58
93
  if (flow.generate) {
59
94
  await flow.callHook("page:generate", generate);
60
95
  globalThis.generate = generate;
package/dist/index.mjs CHANGED
@@ -1,10 +1,12 @@
1
1
  import { createHooks } from 'hookable';
2
2
  import { dirname, resolve, normalize, join, isAbsolute, relative, extname } from 'pathe';
3
3
  import { defineFlowModule, addPlugin, defineNuxtModule, logger, addTemplate, addPluginTemplate, addVitePlugin, useNuxt, resolveAlias, resolveFilesFlow, nuxtCtx, installModule, loadFlowConfig, templateUtils, normalizeTemplate, compileTemplate, normalizePlugin, isIgnoredFlow } from '@monkeyplus/flow-kit';
4
- import { fileURLToPath, pathToFileURL } from 'node:url';
4
+ import { fileURLToPath } from 'url';
5
5
  import { defineUnimportPreset, createUnimport, toImports, scanDirExports } from 'unimport';
6
+ import { pathToFileURL } from 'node:url';
6
7
  import { createUnplugin } from 'unplugin';
7
8
  import { parseURL, parseQuery, joinURL, withoutTrailingSlash } from 'ufo';
9
+ import fs from 'fs';
8
10
  import escapeRE from 'escape-string-regexp';
9
11
  import { camelCase, pascalCase } from 'scule';
10
12
  import { genImport, genDynamicImport, genArrayFromRaw, genString, genObjectFromRawEntries } from 'knitwork';
@@ -27,7 +29,7 @@ import { isExternal as isExternal$1, ExternalsDefaults } from 'externality';
27
29
  import { createHash } from 'node:crypto';
28
30
  import MagicString from 'magic-string';
29
31
 
30
- const version = "5.0.0-rc.8";
32
+ const version = "5.0.0-rc.81";
31
33
 
32
34
  let _distDir = dirname(fileURLToPath(import.meta.url));
33
35
  if (_distDir.endsWith("chunks"))
@@ -92,7 +94,8 @@ const commonPresets = [
92
94
  from: "#_pages",
93
95
  imports: [
94
96
  "definePage",
95
- "defineDinamycPage"
97
+ "defineDynamicPage",
98
+ "defineSharedContext"
96
99
  ]
97
100
  })
98
101
  ];
@@ -224,18 +227,24 @@ function addDeclarationTemplates(ctx) {
224
227
  addTemplate({
225
228
  filename: "types/auto-imports.d.ts",
226
229
  getContents: () => `// Generated by auto imports
227
- ${ctx.generateTypeDecarations({ resolvePath: r })}`
230
+ ${ctx.generateTypeDeclarations({ resolvePath: r })}`
228
231
  });
229
232
  }
230
233
 
231
- async function resolvePagesRoutes() {
234
+ async function resolveFiles(dir) {
232
235
  const nuxt = useNuxt();
233
- const pagesDirs = [...new Set(nuxt.options._layers.map((layer) => resolve(layer.config.srcDir, layer.config.dir?.pages || "pages")))];
234
- const allRoutes = (await Promise.all(pagesDirs.map(async (dir) => {
235
- const files = await resolveFilesFlow(dir, `**/*{${nuxt.options.extensions.join(",")}}`);
236
+ const dirs = [resolve(nuxt.options.srcDir, dir)];
237
+ const allRoutes = (await Promise.all(dirs.map(async (dir2) => {
238
+ const files = await resolveFilesFlow(dir2, `**/*{${nuxt.options.extensions.join(",")}}`);
236
239
  files.sort();
237
- return files.map((file) => {
238
- const segments = relative(dir, file).replace(new RegExp(`${escapeRE(extname(file))}$`), "").split("/").join("_");
240
+ return files.filter((file) => {
241
+ if (file.includes(" copy"))
242
+ return false;
243
+ if (!fs.readFileSync(file, "utf8").includes("export"))
244
+ return false;
245
+ return true;
246
+ }).map((file) => {
247
+ const segments = relative(dir2, file).replace(new RegExp(`${escapeRE(extname(file))}$`), "").split("/").join("_");
239
248
  return {
240
249
  file,
241
250
  name: camelCase(segments)
@@ -244,24 +253,31 @@ async function resolvePagesRoutes() {
244
253
  }))).flat();
245
254
  return allRoutes;
246
255
  }
247
- function normalizePages(pages) {
248
- const imports = pages.map((page) => genImport(page.file, [{ name: "pages", as: page.name }])).join("\n");
256
+ function normalizeExports(files) {
257
+ const imports = files.map((page) => genImport(page.file, page.name)).join("\n");
258
+ const exports = files.reduce((acc, curr) => {
259
+ const name = curr.name;
260
+ return `${name}:typeof ${name}==='function'?${name}():${name},${acc}`;
261
+ }, "");
249
262
  return {
250
263
  imports,
251
- exports: pages.reduce((acc, curr) => {
252
- const name = curr.name;
253
- return `${name}:typeof ${name}==='function'?${name}():${name},${acc}`;
254
- }, "")
264
+ exports
255
265
  };
256
266
  }
257
267
 
258
268
  const pagesTypeTemplate = {
259
- filename: "pages.d.ts",
269
+ filename: "types/pages.d.ts",
260
270
  getContents: ({ options }) => `// Generated by pages discovery
261
271
  export {}
262
272
  declare global {
273
+ type ArrElement<ArrType> = ArrType extends readonly (infer ElementType)[]
274
+ ? ElementType
275
+ : never;
263
276
 
264
- ${options.pages.map((c) => `export type ${pascalCase(c.name)}Context=Awaited<ReturnType<typeof ${genDynamicImport(isAbsolute(c.file) ? relative(options.buildDir, c.file) : c.file, { wrapper: false })}['pages']['locales']['es-ec']['context']>>`).join("\n")}
277
+ ${options.pages.map((c) => {
278
+ const _type = `ArrElement<typeof ${genDynamicImport(isAbsolute(c.file) ? relative(join(options.buildDir, "types"), c.file) : c.file, { wrapper: false })}['default']>`;
279
+ return `export type ${pascalCase(c.name)}Context=Awaited<ReturnType<${_type}['locales']['es-ec']['context']>>`;
280
+ }).join("\n")}
265
281
  }
266
282
  export const pagesNames: string[]
267
283
  `.replaceAll(".ts", "")
@@ -275,37 +291,52 @@ const pagesModule = defineNuxtModule({
275
291
  const runtimeDir = resolve(distDir, "pages/runtime");
276
292
  flow.options.alias["#_pages"] = runtimeDir;
277
293
  const pages = [];
278
- flow.hook("builder:watch", async (event, path) => {
279
- const dirs = [
280
- flow.options.dir.pages,
281
- flow.options.dir.layouts,
282
- flow.options.dir.middleware
283
- ].filter(Boolean);
284
- const pathPattern = new RegExp(`^(${dirs.map(escapeRE).join("|")})/`);
285
- if (event !== "change" && path.match(pathPattern))
286
- await flow.callHook("builder:generateApp");
287
- });
288
- const options = { pages, buildDir: flow.options.buildDir };
294
+ const contexts = [];
295
+ const options = { pages, buildDir: flow.options.buildDir, contexts };
289
296
  addTemplate({
290
297
  ...pagesTypeTemplate,
291
298
  options
292
299
  });
300
+ const pagesDirs = [{ path: resolve(flow.options.srcDir, flow.options.dir.pages) }];
293
301
  flow.options.alias["#pages"] = resolve(flow.options.buildDir, "pages.mjs");
302
+ flow.options.alias["#pagesContexts"] = resolve(flow.options.buildDir, "pages.contexts.mjs");
294
303
  addTemplate({
295
304
  filename: "pages.mjs",
296
305
  async getContents({ options: options2 }) {
297
- const { exports, imports } = normalizePages(options2.pages);
298
- return [imports, `export default {${exports}}`].join("\n");
306
+ const { exports, imports } = normalizeExports(options2.pages);
307
+ const module = [imports, `export default {${exports}}`].join("\n");
308
+ return module;
309
+ },
310
+ options
311
+ });
312
+ addTemplate({
313
+ filename: "pages.contexts.mjs",
314
+ async getContents({ options: options2 }) {
315
+ const { exports, imports } = normalizeExports(options2.contexts);
316
+ const module = [imports, `export default {${exports}}`].join("\n");
317
+ return module;
299
318
  },
300
319
  options
301
320
  });
302
321
  flow.hook("app:templates", async () => {
303
- options.pages = await resolvePagesRoutes();
322
+ options.pages = await resolveFiles(flow.options.dir?.pages || "pages");
323
+ });
324
+ flow.hook("app:templates", async () => {
325
+ options.contexts = await resolveFiles("shared/contexts");
304
326
  });
305
327
  flow.hook("prepare:types", ({ references }) => {
306
- references.push({ path: resolve(flow.options.buildDir, "pages.d.ts") });
328
+ references.push({ path: resolve(flow.options.buildDir, "types/pages.d.ts") });
307
329
  });
308
- addPlugin({ src: resolve(runtimeDir, "plugin") });
330
+ flow.hook("builder:watch", async (event, path) => {
331
+ if (!["add", "unlink", "change"].includes(event))
332
+ return;
333
+ if (path.includes(" copy"))
334
+ return;
335
+ const fPath = resolve(flow.options.rootDir, path);
336
+ if (pagesDirs.find((dir) => fPath.startsWith(dir.path)))
337
+ await flow.callHook("builder:generateApp");
338
+ });
339
+ addPlugin(resolve(runtimeDir, "pages"));
309
340
  }
310
341
  });
311
342
 
@@ -333,7 +364,7 @@ const createClient = async (flow) => {
333
364
  if (vite)
334
365
  vite?.ws?.send({ type: "full-reload" });
335
366
  };
336
- const doReload = debounce(_doReload, 60);
367
+ const doReload = debounce(_doReload, 75);
337
368
  flow.hook("bundler:change", () => {
338
369
  doReload();
339
370
  });
@@ -344,11 +375,11 @@ const createClient = async (flow) => {
344
375
  };
345
376
  const builClient = async (flow) => {
346
377
  return await build$1({
378
+ base: flow.options.dev ? "/" : flow.options.app.baseURL,
347
379
  root: flow.options.rootDir,
348
380
  mode: "production",
349
381
  build: {
350
- assetsDir: "scripts",
351
- target: "es2017",
382
+ target: "es2015",
352
383
  outDir: ".vite",
353
384
  manifest: true
354
385
  }
@@ -389,26 +420,27 @@ const viteModule = defineFlowModule({
389
420
  }
390
421
  });
391
422
  } else {
392
- flow.hook("modules:done", async () => {
423
+ const file = resolve(flow.options.rootDir, ".vite/manifest.json");
424
+ addTemplate({
425
+ filename: "viteManifest.mjs",
426
+ async getContents() {
427
+ return [
428
+ "import fs from 'fs';",
429
+ `export default ()=>{
430
+ const manifest =JSON.parse(fs.readFileSync("${file}", 'utf8'));
431
+ return {manifest,base:'${_options.dir}'}
432
+ }`
433
+ ].join("\n");
434
+ }
435
+ });
436
+ flow.hook("build:before", async () => {
393
437
  const start = Date.now();
394
438
  logger$1.info("Building client...");
395
439
  await builClient(flow);
396
- const file = resolve(flow.options.rootDir, ".vite/manifest.json");
397
- const manifest = await fse.readFile(file, "utf8");
398
440
  logger$1.success(`Client build in ${Date.now() - start}ms`);
399
- addTemplate({
400
- filename: "viteManifest.mjs",
401
- async getContents() {
402
- return [
403
- "export default ()=>(",
404
- manifest,
405
- ")"
406
- ].join("\n");
407
- }
408
- });
409
441
  });
410
442
  flow.hook("generate:before", async () => {
411
- const files = resolve(flow.options.rootDir, ".vite/scripts");
443
+ const files = resolve(flow.options.rootDir, ".vite/assets");
412
444
  await fse.copy(files, resolve(flow.options.generate.dir, "assets"));
413
445
  });
414
446
  }
@@ -462,6 +494,7 @@ async function initNitro(flow) {
462
494
  ...flow.options.runtimeConfig,
463
495
  app: {
464
496
  ...flow.options.runtimeConfig.app,
497
+ baseURL: flow.options.dev ? "/" : flow.options.app.baseURL,
465
498
  rootDir: flow.options.rootDir,
466
499
  locale: flow.options.locale
467
500
  },
@@ -489,7 +522,8 @@ async function initNitro(flow) {
489
522
  externals: {
490
523
  inline: [
491
524
  ...flow.options.dev ? [] : ["eta", "@monkeyplus/", "@vue/", "@nuxt/", flow.options.buildDir],
492
- "@monkeyplus/flow/dist"
525
+ "@monkeyplus/flow/dist",
526
+ "C:/Users/gnu/Documents/GitHub/flow/packages/flow/dist/app"
493
527
  ]
494
528
  },
495
529
  alias: {
@@ -500,7 +534,8 @@ async function initNitro(flow) {
500
534
  ...flow.options.alias
501
535
  },
502
536
  rollupConfig: {
503
- plugins: []
537
+ plugins: [],
538
+ external: [""]
504
539
  }
505
540
  });
506
541
  await flow.callHook("nitro:config", nitroConfig);
@@ -1092,6 +1127,8 @@ const buildServer = async (ctx) => {
1092
1127
  "/__vue-jsx",
1093
1128
  "#app",
1094
1129
  /(nuxt|nuxt3)\/(dist|src|app)/,
1130
+ /flow\/(dist|src|app)/,
1131
+ /flow\/modules\/(content|icons|images|netlify|netlify-cms|seo|sitemap|vue)/,
1095
1132
  /@monkeyplus\/flow\/(dist|src|app)/,
1096
1133
  /@nuxt\/nitro\/(dist|src)/
1097
1134
  ]
@@ -1169,9 +1206,11 @@ const buildServer = async (ctx) => {
1169
1206
  await onBuild();
1170
1207
  ctx.flow.callHook("bundler:change", {});
1171
1208
  };
1172
- const doBuild = debounce(_doBuild);
1209
+ const doBuild = debounce(_doBuild, 50);
1173
1210
  await _doBuild();
1174
1211
  viteServer.watcher.on("all", (_event, file) => {
1212
+ if (file.includes("/pages/"))
1213
+ return;
1175
1214
  file = normalize(file);
1176
1215
  if (file.indexOf(ctx.flow.options.buildDir) === 0)
1177
1216
  return;
@@ -1291,6 +1330,7 @@ async function bundleVite(flow) {
1291
1330
  include: []
1292
1331
  },
1293
1332
  build: {
1333
+ ssr: true,
1294
1334
  rollupOptions: {
1295
1335
  output: { sanitizeFileName: sanitizeFilePath },
1296
1336
  input: resolve(flow.options.appDir, "entry")
@@ -1327,6 +1367,8 @@ async function bundleVite(flow) {
1327
1367
  flow.hook("vite:serverCreated", (server) => {
1328
1368
  ctx.nuxt.hook("app:templatesGenerated", () => {
1329
1369
  for (const [id, mod] of server.moduleGraph.idToModuleMap) {
1370
+ if (id.includes("pages."))
1371
+ server.moduleGraph.invalidateModule(mod);
1330
1372
  if (id.startsWith("\0virtual:"))
1331
1373
  server.moduleGraph.invalidateModule(mod);
1332
1374
  }
@@ -1368,8 +1410,7 @@ function watch(flow) {
1368
1410
  "node_modules"
1369
1411
  ]
1370
1412
  });
1371
- const watchHook = debounce((event, path) => flow.callHook("builder:watch", event, normalize(path)));
1372
- watcher.on("all", watchHook);
1413
+ watcher.on("all", (event, path) => flow.callHook("builder:watch", event, normalize(path)));
1373
1414
  flow.hook("close", () => watcher.close());
1374
1415
  return watcher;
1375
1416
  }
@@ -1,6 +1,9 @@
1
1
  import { joinURL, withTrailingSlash } from "ufo";
2
- const buildPages = (page) => (location, language) => {
3
- const locales = Object.entries(page.locales);
2
+ const buildPages = (page) => (location, language, _locales) => {
3
+ const locales = _locales.map((key) => {
4
+ const _page = page.locales[key];
5
+ return [key, _page];
6
+ }).filter((el) => !!el[1]);
4
7
  return locales.map(([locale, localePage]) => {
5
8
  const [_language, _location] = locale.split("-");
6
9
  const name = joinURL("/", _location, _language, page.name);
@@ -1,3 +1,10 @@
1
- import type { DynamicPage, SimplePage } from '@monkeyplus/flow-schema';
2
- export declare function definePage(page: SimplePage): SimplePage;
3
- export declare function defineDinamycPage(page: DynamicPage): DynamicPage;
1
+ import type { DynamicPage, PageCtx, SimplePage } from '@monkeyplus/flow-schema';
2
+ export declare function definePage<T>(...pages: SimplePage<T>[]): SimplePage<T>[];
3
+ export declare function defineDynamicPage<T>(...pages: DynamicPage<T>[]): DynamicPage<T>[];
4
+ export interface SharedContext {
5
+ assign?: 'global' | 'local';
6
+ merge?: boolean;
7
+ setup: (cxt: PageCtx) => any;
8
+ locales?: Record<string, (ctx: PageCtx) => any>;
9
+ }
10
+ export declare function defineSharedContext(shared: SharedContext): SharedContext;
@@ -1,6 +1,13 @@
1
- export function definePage(page) {
2
- return page;
1
+ export function definePage(...pages) {
2
+ return pages;
3
3
  }
4
- export function defineDinamycPage(page) {
5
- return page;
4
+ export function defineDynamicPage(...pages) {
5
+ return pages.map((page) => {
6
+ if (!page.name.endsWith("/**"))
7
+ page.name = `${page.name}/**`;
8
+ return page;
9
+ });
10
+ }
11
+ export function defineSharedContext(shared) {
12
+ return shared;
6
13
  }
@@ -0,0 +1,96 @@
1
+ import { joinURL } from "ufo";
2
+ import consola from "consola";
3
+ import { definePage } from "./helpers/index.mjs";
4
+ import { defineFlowPlugin, useRuntimeConfig } from "#app";
5
+ import pages from "#build/pages";
6
+ import contexts from "#build/pages.contexts";
7
+ export default defineFlowPlugin(async (flow) => {
8
+ const { app } = useRuntimeConfig();
9
+ const allPages = [];
10
+ const basePages = Object.entries(pages);
11
+ consola.success("Parsed %i pages files", basePages.length);
12
+ basePages.forEach(([name, _pages]) => {
13
+ const __pages = Array.isArray(_pages) ? _pages : [_pages];
14
+ __pages.forEach((page) => {
15
+ const { getPages } = definePage({
16
+ name,
17
+ ...page
18
+ });
19
+ const _pages2 = getPages(app.locale.location, app.locale.language, app.locale.locales);
20
+ _pages2.forEach((page2) => {
21
+ flow.router.byUrl.insert(page2.url, page2.context);
22
+ flow.router.byName.insert(page2.name, page2.context);
23
+ allPages.push(page2.context);
24
+ });
25
+ });
26
+ });
27
+ const cache = {};
28
+ async function getUrl(namePage, localeCode) {
29
+ const code = localeCode || this?.getLocale()?.code;
30
+ const [lang, loc] = code.split("-");
31
+ const name = joinURL("/", loc, lang, namePage);
32
+ const { path, params, page } = flow.router.byName.lookup(name) || {};
33
+ if (params?._ && page.dynamic) {
34
+ if (!cache[path]) {
35
+ cache[path] = this.defineCachedFunction(async (_ctx) => {
36
+ return await page.dynamic.method(_ctx);
37
+ }, { maxAge: 8, getKey: () => path, swr: false });
38
+ }
39
+ const fn = cache[path];
40
+ const list = await fn({ utils: this, locale: this.getLocale() });
41
+ const dPage = list.find((el) => el.name === params._);
42
+ return dPage ? path.replace("**", dPage.url) : "/404";
43
+ }
44
+ return path || "/404";
45
+ }
46
+ async function getUrls(withLocale = false) {
47
+ const urls = [];
48
+ for (const page of allPages) {
49
+ if (page.path.includes("/**") && page.page.dynamic) {
50
+ const dPages = await page.page.dynamic.method({
51
+ locale: page.locale,
52
+ utils: Object.assign({ getLocale: () => page.locale }, flow.app.utils),
53
+ chunks: {},
54
+ page: {}
55
+ });
56
+ dPages.forEach((dPage) => {
57
+ const _path = joinURL(page.path.replace("/**", ""), dPage.url);
58
+ urls.push(withLocale ? { url: _path, locale: page.locale.code, name: joinURL(page.name, dPage.name) } : _path);
59
+ });
60
+ } else {
61
+ const url = page.path.replaceAll("*", "");
62
+ urls.push(withLocale ? { url, locale: page.locale.code, name: page.name } : url);
63
+ }
64
+ }
65
+ return urls.sort();
66
+ }
67
+ async function getSharedContext(ctx) {
68
+ const entries = Object.entries(contexts);
69
+ if (!entries.length)
70
+ return {};
71
+ const _contexts = await Promise.all(entries.map(async ([key, method]) => {
72
+ const data = await method.setup(ctx);
73
+ const setupLocal = method?.locales?.[ctx.locale.code];
74
+ let dataLocal = {};
75
+ if (setupLocal)
76
+ dataLocal = await setupLocal(ctx);
77
+ const obj = method.merge ? { ...data, ...dataLocal } : { [key]: { ...data, ...dataLocal } };
78
+ return obj;
79
+ }));
80
+ return _contexts.reduce((acc, curr) => {
81
+ return {
82
+ ...acc,
83
+ ...curr
84
+ };
85
+ }, {});
86
+ }
87
+ flow.setUtil("getUrl", getUrl);
88
+ flow.setUtil("getUrls", getUrls);
89
+ flow.setUtil("getPages", () => allPages);
90
+ flow.setUtil("getSharedContext", getSharedContext);
91
+ return {
92
+ provide: {
93
+ pages: { allPages }
94
+ }
95
+ };
96
+ });
@@ -5,7 +5,8 @@ export const generateBundle = (config, bundle, _id) => {
5
5
  const chunks = [];
6
6
  chunk2.imports?.forEach((file) => {
7
7
  const importee = bundle[file];
8
- if (file.startsWith("_") && !seen.has(file)) {
8
+ const isChunk = file.startsWith("_") || importee.isEntry;
9
+ if (isChunk && !seen.has(file)) {
9
10
  seen.add(file);
10
11
  chunks.push(...getImportedChunks(importee, seen));
11
12
  chunks.push(importee);
@@ -36,7 +37,7 @@ export const generateBundle = (config, bundle, _id) => {
36
37
  analyzedChunk.set(chunk2, 1);
37
38
  chunk2.imports?.forEach((file) => {
38
39
  const importee = bundle[file];
39
- if (file.startsWith("_"))
40
+ if (file.startsWith("_") || importee.isEntry)
40
41
  tags.push(...getCssTagsForChunk(importee, publicBase2, seen));
41
42
  });
42
43
  }
@@ -71,7 +72,7 @@ export const generateBundle = (config, bundle, _id) => {
71
72
  export const externalRE = /^(https?:)?\/\//;
72
73
  export const isExternalUrl = (url) => externalRE.test(url);
73
74
  function toPublicPath(filename, publicBase) {
74
- return isExternalUrl(filename) ? filename : joinURL(publicBase, filename.replace("scripts", "assets"));
75
+ return isExternalUrl(filename) ? filename : joinURL(publicBase, filename);
75
76
  }
76
77
  const unaryTags = new Set(["link", "meta", "base"]);
77
78
  function serializeTag({ tag, attrs, children }, indent = "") {
@@ -1,13 +1,14 @@
1
1
  import logger from "consola";
2
+ import { joinURL } from "ufo";
2
3
  import { generateBundle } from "./injectManifest.mjs";
3
4
  import { defineFlowPlugin } from "#app";
4
5
  import manifest from "#viteManifest";
5
6
  export default defineFlowPlugin((flow) => {
6
7
  if (typeof manifest === "function") {
7
- const _manifest = manifest();
8
8
  flow.hook("page:chunks", (bundle, chunks) => {
9
9
  try {
10
- const chunk = generateBundle(flow.$config.app || {}, _manifest, `client/pages/${bundle}.ts`);
10
+ const data = manifest();
11
+ const chunk = generateBundle(flow.$config.app || {}, data.manifest, joinURL("/", data.base, `${bundle}.ts`).replace("/", ""));
11
12
  if (chunk) {
12
13
  chunks.head.push(chunk.head);
13
14
  chunks.body.push(chunk.body);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monkeyplus/flow",
3
- "version": "5.0.0-rc.8",
3
+ "version": "5.0.0-rc.81",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",
@@ -25,52 +25,52 @@
25
25
  "dist"
26
26
  ],
27
27
  "dependencies": {
28
- "@monkeyplus/flow-cli": "5.0.0-rc.8",
29
- "@monkeyplus/flow-kit": "5.0.0-rc.8",
30
- "@monkeyplus/flow-schema": "5.0.0-rc.8",
28
+ "@monkeyplus/flow-cli": "5.0.0-rc.81",
29
+ "@monkeyplus/flow-kit": "5.0.0-rc.81",
30
+ "@monkeyplus/flow-schema": "5.0.0-rc.81",
31
31
  "@rollup/plugin-replace": "^4.0.0",
32
32
  "@vueuse/head": "^0.7.6",
33
- "c12": "^0.2.7",
33
+ "c12": "^0.2.8",
34
34
  "chokidar": "^3.5.3",
35
35
  "consola": "^2.15.3",
36
36
  "defu": "^6.0.0",
37
- "esbuild": "^0.14.38",
37
+ "esbuild": "^0.14.49",
38
38
  "escape-string-regexp": "^5.0.0",
39
- "esno": "^0.14.1",
39
+ "esno": "^0.16.3",
40
40
  "eta": "^1.12.3",
41
- "externality": "^0.2.1",
41
+ "externality": "^0.2.2",
42
42
  "fs-extra": "^10.1.0",
43
43
  "get-port-please": "^2.5.0",
44
- "globby": "^13.1.1",
45
- "h3": "^0.7.4",
44
+ "globby": "^13.1.2",
45
+ "h3": "^0.7.10",
46
46
  "hookable": "^5.1.1",
47
- "jiti": "^1.13.0",
48
- "knitwork": "^0.1.1",
49
- "listhen": "^0.2.10",
47
+ "jiti": "^1.14.0",
48
+ "knitwork": "^0.1.2",
49
+ "listhen": "^0.2.13",
50
50
  "magic-string": "^0.26.2",
51
- "mlly": "^0.5.2",
51
+ "mlly": "^0.5.4",
52
52
  "mri": "^1.2.0",
53
- "nitropack": "^0.4.4",
54
- "pathe": "^0.2.0",
53
+ "nitropack": "^0.4.12",
54
+ "pathe": "^0.3.2",
55
55
  "perfect-debounce": "^0.1.3",
56
56
  "radix3": "^0.1.2",
57
57
  "unenv": "^0.5.2",
58
58
  "ohmyfetch": "^0.4.18",
59
- "node-fetch-native": "^0.1.3",
60
- "rollup": "^2.72.1",
61
- "rollup-plugin-visualizer": "^5.6.0",
59
+ "node-fetch-native": "^0.1.4",
60
+ "rollup": "^2.77.0",
61
+ "rollup-plugin-visualizer": "^5.7.1",
62
62
  "scule": "^0.2.1",
63
- "ufo": "^0.8.3",
63
+ "ufo": "^0.8.5",
64
64
  "unctx": "^1.1.4",
65
- "unimport": "^0.2.1",
66
- "unplugin": "^0.6.3",
65
+ "unimport": "^0.4.5",
66
+ "unplugin": "^0.7.2",
67
67
  "untyped": "^0.4.4",
68
68
  "vite": "^2.9.9",
69
- "vue": "^3.2.33"
69
+ "vue": "^3.2.37"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/fs-extra": "^9.0.13",
73
- "vue-router": "^4.0.15"
73
+ "vue-router": "^4.1.2"
74
74
  },
75
75
  "engines": {
76
76
  "node": "^16.11.0 || ^17.0.0 || ^18.0.0"
@@ -1,56 +0,0 @@
1
- import { joinURL } from "ufo";
2
- import consola from "consola";
3
- import { definePage } from "./helpers/index.mjs";
4
- import { defineFlowPlugin, useRuntimeConfig } from "#app";
5
- import pages from "#pages";
6
- export default defineFlowPlugin(async (flow) => {
7
- const { app } = useRuntimeConfig();
8
- const allPages = [];
9
- const basePages = Object.entries(pages);
10
- consola.success("Parsed %i pages", basePages.length);
11
- basePages.forEach(([name, page]) => {
12
- const { getPages } = definePage({
13
- name,
14
- ...page
15
- });
16
- const _pages = getPages(app.locale.location, app.locale.language);
17
- _pages.forEach((page2) => {
18
- flow.router.byUrl.insert(page2.url, page2.context);
19
- flow.router.byName.insert(page2.name, page2.context);
20
- allPages.push(page2.context);
21
- });
22
- });
23
- function getUrl(namePage, localeCode) {
24
- const code = localeCode || this?.getLocale()?.code;
25
- const [lang, loc] = code.split("-");
26
- const name = joinURL("/", loc, lang, namePage);
27
- const { path } = flow.router.byName.lookup(name) || {};
28
- return path || "/404";
29
- }
30
- async function getUrls(withLocale = false) {
31
- const urls = [];
32
- for (const page of allPages) {
33
- if (!page.path.includes("/**")) {
34
- urls.push(withLocale ? { url: page.path, locale: page.locale.code, name: page.name } : page.path);
35
- } else {
36
- const dPages = await page.page.dynamic.method({
37
- locale: page.locale,
38
- utils: Object.assign({ getLocale: () => page.locale }, flow.app.utils)
39
- });
40
- dPages.forEach((dPage) => {
41
- const _path = joinURL(page.path.replace("/**", ""), dPage.url);
42
- urls.push(withLocale ? { url: _path, locale: page.locale.code, name: joinURL(page.name, dPage.name) } : _path);
43
- });
44
- }
45
- }
46
- return urls.sort();
47
- }
48
- flow.setUtil("getUrl", getUrl);
49
- flow.setUtil("getUrls", getUrls);
50
- flow.setUtil("getPages", () => allPages);
51
- return {
52
- provide: {
53
- pages: { allPages }
54
- }
55
- };
56
- });
File without changes