fuzzyworld-tools / files / vite / index.js
index.js
| 1 | // Vite plugin for apps on apps.fuzzyworld.net. |
| 2 | // |
| 3 | // import fuzzyworld from 'fuzzyworld-tools/vite'; |
| 4 | // export default defineConfig({ plugins: [fuzzyworld()] }); |
| 5 | // |
| 6 | // Sets `base` to `/<app>/`, where <app> is `fuzzyworld.app` in package.json, so every |
| 7 | // asset URL stays inside the app's own path on the shared origin. `fw deploy` checks |
| 8 | // the built output (manifest, service worker scope) before anything is uploaded. |
| 9 | import fs from 'node:fs'; |
| 10 | import path from 'node:path'; |
| 11 | |
| 12 | // Nearest package.json with a "fuzzyworld" section, from `start` upwards. Vite's `root` |
| 13 | // is often a subfolder (e.g. root: 'src'), while package.json sits at the repo root. |
| 14 | function findPackageJson(start) { |
| 15 | for (let dir = path.resolve(start); ; dir = path.dirname(dir)) { |
| 16 | const p = path.join(dir, 'package.json'); |
| 17 | if (fs.existsSync(p) && JSON.parse(fs.readFileSync(p, 'utf8')).fuzzyworld) return p; |
| 18 | if (path.dirname(dir) === dir) return null; |
| 19 | } |
| 20 | } |
| 21 | |
| 22 | export function readAppConfig(root = process.cwd()) { |
| 23 | const pkgPath = findPackageJson(root); |
| 24 | if (!pkgPath) { |
| 25 | throw new Error(`fuzzyworld: add "fuzzyworld": { "app": "<name>" } to package.json (searched upwards from ${root})`); |
| 26 | } |
| 27 | const cfg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')).fuzzyworld; |
| 28 | if (!cfg.app) { |
| 29 | throw new Error(`fuzzyworld: add "app" to the "fuzzyworld" section of ${pkgPath}`); |
| 30 | } |
| 31 | if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(cfg.app)) { |
| 32 | throw new Error(`fuzzyworld: invalid app name "${cfg.app}"`); |
| 33 | } |
| 34 | return cfg; |
| 35 | } |
| 36 | |
| 37 | export default function fuzzyworld() { |
| 38 | return { |
| 39 | name: 'fuzzyworld', |
| 40 | config(config, { command }) { |
| 41 | const root = config.root ? path.resolve(config.root) : process.cwd(); |
| 42 | // `fw deploy --as <name>` (lib/deploy.mjs) builds the same app under another path. |
| 43 | const app = process.env.FW_APP || readAppConfig(root).app; |
| 44 | const base = `/${app}/`; |
| 45 | // `vite dev` keeps the developer's own base; builds always use the app path. |
| 46 | if (command === 'build' && config.base && config.base !== base && config.base !== './') { |
| 47 | console.warn(`fuzzyworld: overriding base "${config.base}" with "${base}"`); |
| 48 | } |
| 49 | return command === 'build' ? { base } : {}; |
| 50 | }, |
| 51 | }; |
| 52 | } |