From 871f33b831c3e8b20c9ef51823882d0ae8dbcc0b Mon Sep 17 00:00:00 2001 From: Marvin Hagemeister Date: Tue, 27 Apr 2021 00:02:18 +0200 Subject: [PATCH 01/10] WIP --- examples/demo/public/index.tsx | 3 + examples/demo/public/pages2/bar.jsx | 3 + .../demo/public/pages2/foo/[id2]/index.jsx | 3 + examples/demo/public/pages2/foo/[id].jsx | 3 + examples/demo/public/pages2/foo/index.jsx | 3 + examples/demo/public/pages2/index.jsx | 3 + examples/demo/wmr.config.ts | 3 +- packages/wmr/src/cli.js | 3 + packages/wmr/src/lib/normalize-options.js | 1 + packages/wmr/src/lib/plugins.js | 3 + packages/wmr/src/plugins/fs-routes-plugin.js | 86 +++++++++++++++++++ packages/wmr/src/wmr-middleware.js | 2 + packages/wmr/types.d.ts | 1 + 13 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 examples/demo/public/pages2/bar.jsx create mode 100644 examples/demo/public/pages2/foo/[id2]/index.jsx create mode 100644 examples/demo/public/pages2/foo/[id].jsx create mode 100644 examples/demo/public/pages2/foo/index.jsx create mode 100644 examples/demo/public/pages2/index.jsx create mode 100644 packages/wmr/src/plugins/fs-routes-plugin.js diff --git a/examples/demo/public/index.tsx b/examples/demo/public/index.tsx index c75a72f31..725647273 100644 --- a/examples/demo/public/index.tsx +++ b/examples/demo/public/index.tsx @@ -4,6 +4,9 @@ import Home from './pages/home.js'; import NotFound from './pages/_404.js'; import Header from './header.tsx'; // import './style.css'; +import { routes } from 'builtins:fs-routes'; + +console.log(routes); const sleep = t => new Promise(r => setTimeout(r, t)); diff --git a/examples/demo/public/pages2/bar.jsx b/examples/demo/public/pages2/bar.jsx new file mode 100644 index 000000000..ebfad70ea --- /dev/null +++ b/examples/demo/public/pages2/bar.jsx @@ -0,0 +1,3 @@ +export default function Page() { + return

bar

; +} diff --git a/examples/demo/public/pages2/foo/[id2]/index.jsx b/examples/demo/public/pages2/foo/[id2]/index.jsx new file mode 100644 index 000000000..5fb2571f3 --- /dev/null +++ b/examples/demo/public/pages2/foo/[id2]/index.jsx @@ -0,0 +1,3 @@ +export default function Page() { + return

dynamic id index

; +} diff --git a/examples/demo/public/pages2/foo/[id].jsx b/examples/demo/public/pages2/foo/[id].jsx new file mode 100644 index 000000000..4a7dd954b --- /dev/null +++ b/examples/demo/public/pages2/foo/[id].jsx @@ -0,0 +1,3 @@ +export default function Page() { + return

dynamic id

; +} diff --git a/examples/demo/public/pages2/foo/index.jsx b/examples/demo/public/pages2/foo/index.jsx new file mode 100644 index 000000000..7e56d0164 --- /dev/null +++ b/examples/demo/public/pages2/foo/index.jsx @@ -0,0 +1,3 @@ +export default function Page() { + return

foo

; +} diff --git a/examples/demo/public/pages2/index.jsx b/examples/demo/public/pages2/index.jsx new file mode 100644 index 000000000..b804dba49 --- /dev/null +++ b/examples/demo/public/pages2/index.jsx @@ -0,0 +1,3 @@ +export default function Page() { + return

index

; +} diff --git a/examples/demo/wmr.config.ts b/examples/demo/wmr.config.ts index e8dc73afa..d04b194ef 100644 --- a/examples/demo/wmr.config.ts +++ b/examples/demo/wmr.config.ts @@ -2,6 +2,7 @@ export default function () { return { alias: { 'src/*': 'src' - } + }, + pagesDir: 'public/pages2' }; } diff --git a/packages/wmr/src/cli.js b/packages/wmr/src/cli.js index 356f9677b..98a2d7768 100644 --- a/packages/wmr/src/cli.js +++ b/packages/wmr/src/cli.js @@ -16,6 +16,7 @@ function bool(v) { // global options prog .option('--cwd', 'The working directory - equivalent to "(cd FOO && wmr)"') + .option('--pagesDir', 'Directory for filesystem-based routes(default: /pages)') // Setting env variables isn't common knowledege for many windows users. Much // easier to pass a flag to our binary instead. .option('--debug', 'Print internal debugging messages to the console. Same as setting DEBUG=true'); @@ -29,6 +30,7 @@ prog .option('--visualize', 'Launch interactive bundle visualizer') .action(opts => { opts.minify = opts.minify !== false && !/false|0/.test(opts.minify); + console.log(opts); run(build(opts)); }); @@ -54,6 +56,7 @@ prog .option('--profile', 'Generate build statistics') .option('--reload', 'Switch off hmr and reload on file saves') .action(opts => { + console.log(opts); opts.optimize = !/false|0/.test(opts.compress); opts.compress = bool(opts.compress); if (/true/.test(process.env.PROFILE || '')) opts.profile = true; diff --git a/packages/wmr/src/lib/normalize-options.js b/packages/wmr/src/lib/normalize-options.js index b6e24da5c..f10471179 100644 --- a/packages/wmr/src/lib/normalize-options.js +++ b/packages/wmr/src/lib/normalize-options.js @@ -28,6 +28,7 @@ export async function normalizeOptions(options, mode, configWatchFiles = []) { options.middleware = []; options.features = { preact: true }; options.alias = options.alias || options.aliases || {}; + options.pagesDir = join(options.cwd, options.pagesDir || 'pages'); // `wmr` / `wmr start` is a development command. // `wmr build` / `wmr serve` are production commands. diff --git a/packages/wmr/src/lib/plugins.js b/packages/wmr/src/lib/plugins.js index 04848bda9..bbb0301ec 100644 --- a/packages/wmr/src/lib/plugins.js +++ b/packages/wmr/src/lib/plugins.js @@ -1,3 +1,4 @@ +import path from 'path'; import htmPlugin from '../plugins/htm-plugin.js'; import sucrasePlugin from '../plugins/sucrase-plugin.js'; import wmrPlugin from '../plugins/wmr/plugin.js'; @@ -21,6 +22,7 @@ import nodeBuiltinsPlugin from '../plugins/node-builtins-plugin.js'; import dynamicImportVars from '@rollup/plugin-dynamic-import-vars'; import visualizer from 'rollup-plugin-visualizer'; import { defaultLoaders } from './default-loaders.js'; +import fsRoutesPlugin from '../plugins/fs-routes-plugin.js'; /** * @param {import("wmr").Options} options @@ -44,6 +46,7 @@ export function getPlugins(options) { jsonPlugin({ cwd }), bundlePlugin({ inline: !production, cwd }), aliasPlugin({ alias, cwd: root }), + fsRoutesPlugin({ pagesDir: options.pagesDir, cwd, publicPath: options.publicPath }), sucrasePlugin({ typescript: true, sourcemap, diff --git a/packages/wmr/src/plugins/fs-routes-plugin.js b/packages/wmr/src/plugins/fs-routes-plugin.js new file mode 100644 index 000000000..6ed2e4c70 --- /dev/null +++ b/packages/wmr/src/plugins/fs-routes-plugin.js @@ -0,0 +1,86 @@ +import { promises as fs } from 'fs'; +import path from 'path'; + +/** + * Traverse the pages directory and retrieve all routes. + * @param {string} root Directory to start search from + * @param {string} [dir] + */ +async function readRecursive(root, dir = root) { + const mixed = await fs.readdir(dir); + + /** @type {string[]} */ + const routes = []; + + await Promise.all( + mixed.map(async fileOrDir => { + const absolute = path.join(dir, fileOrDir); + if (/\.[tj]sx?$/.test(fileOrDir)) { + const name = path.basename(fileOrDir, path.extname(fileOrDir)); + const routePath = name === 'index' ? path.relative(root, dir) : path.relative(root, path.join(dir, name)); + routes.push(routePath); + } + + const stats = await fs.lstat(absolute); + if (stats.isDirectory()) { + routes.push(...(await readRecursive(root, absolute))); + } + }) + ); + + return routes; +} + +/** + * Convert JSX to HTM + * @param {object} options + * @param {string} options.pagesDir Controls whether files are processed to transform JSX. + * @param {string} options.cwd + * @param {string} options.publicPath + * @returns {import('wmr').Plugin} + */ +export default function fsRoutesPlugin({ pagesDir, publicPath, cwd }) { + const PUBLIC = 'builtins:fs-routes'; + const INTERNAL = '\0builtins:fs-routes'; + return { + name: 'fs-router', + resolveId(id) { + if (id === PUBLIC) { + return INTERNAL; + } + }, + async load(id) { + if (id !== INTERNAL) return; + + const rawRoutes = await readRecursive(pagesDir); + + const routes = rawRoutes.map(raw => { + const url = '/' + raw.split(path.sep).join(path.posix.sep); + const route = url.replace(/\[(\w+)\]/g, (m, g) => `:${g}`); + return { url, route }; + }); + + const base = path.join(cwd, path.relative(cwd, pagesDir)).split(path.sep).join(path.posix.sep); + + console.log(base, cwd); + + const routesStr = routes + .map(route => { + return `{ + route: ${JSON.stringify(route.route)}, + load: () => import("${base}${route.url}") + }`; + }) + .join(', '); + + console.log(routesStr); + + return `export const routes = [${routesStr}]`; + }, + transform(code, id) { + if (id !== INTERNAL) return; + + console.log(code); + } + }; +} diff --git a/packages/wmr/src/wmr-middleware.js b/packages/wmr/src/wmr-middleware.js index 7903048d6..bde391649 100644 --- a/packages/wmr/src/wmr-middleware.js +++ b/packages/wmr/src/wmr-middleware.js @@ -420,9 +420,11 @@ export const TRANSFORMS = { // const resolved = await NonRollup.resolveId(spec, importer); let originalSpec = spec; const resolved = await NonRollup.resolveId(spec, file); + console.log('RESOLVED', resolved, spec); if (resolved) { spec = typeof resolved == 'object' ? resolved.id : resolved; if (/^(\/|\\|[a-z]:\\)/i.test(spec)) { + console.log(' spec', spec, file); spec = relative(dirname(file), spec).split(sep).join(posix.sep); if (!/^\.?\.?\//.test(spec)) { spec = './' + spec; diff --git a/packages/wmr/types.d.ts b/packages/wmr/types.d.ts index 493ddb2e3..4d85fa411 100644 --- a/packages/wmr/types.d.ts +++ b/packages/wmr/types.d.ts @@ -35,6 +35,7 @@ declare module 'wmr' { host: string; port: number; root: string; + pagesDir: string; out: string; overlayDir: string; sourcemap: boolean; From aff73c91b91e48e0e1f2be2fdc0e5ea19f12183a Mon Sep 17 00:00:00 2001 From: Marvin Hagemeister Date: Tue, 27 Apr 2021 00:30:52 +0200 Subject: [PATCH 02/10] WIP --- examples/demo/public/header.tsx | 1 + examples/demo/public/index.tsx | 12 ++++++++++++ examples/demo/public/pages/page-routes.js | 18 ++++++++++++++++++ packages/wmr/src/plugins/fs-routes-plugin.js | 6 +----- packages/wmr/src/wmr-middleware.js | 8 ++++++-- 5 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 examples/demo/public/pages/page-routes.js diff --git a/examples/demo/public/header.tsx b/examples/demo/public/header.tsx index 516cdb608..1f5d625a8 100644 --- a/examples/demo/public/header.tsx +++ b/examples/demo/public/header.tsx @@ -16,6 +16,7 @@ export default function Header() { Alias outside Error Meta-Tags + FS Routes