catalyst-core 0.3.0-beta.3 → 0.3.0-beta.4
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.
- package/dist/server/expressServer.js +7 -0
- package/dist/server/renderer/document/Body.jsx +4 -1
- package/dist/vite/FastRefresh.jsx +3 -1
- package/dist/vite/loadCustomViteConfig.js +28 -0
- package/dist/vite/node-loader.mjs +30 -2
- package/dist/vite/resolveDevServerConfig.js +45 -0
- package/dist/vite/vite.config.client.js +1 -1
- package/dist/vite/vite.config.js +31 -9
- package/dist/vite/vite.config.server.js +5 -1
- package/package.json +2 -1
- package/test/vite/resolveDevServerConfig.test.js +113 -0
|
@@ -10,6 +10,7 @@ import pc from "picocolors"
|
|
|
10
10
|
import fs from "fs"
|
|
11
11
|
const { cyan, yellow, green } = pc
|
|
12
12
|
|
|
13
|
+
import { toMountPathPrefix } from "../vite/resolveDevServerConfig.js"
|
|
13
14
|
import { validateMiddleware, safeCall } from "./utils/validator.js"
|
|
14
15
|
import { botDetectionMiddleware } from "./utils/botDetectionMiddleware.js"
|
|
15
16
|
import { cjsRequire } from "./utils/cjsRequire.js"
|
|
@@ -208,6 +209,12 @@ async function createServer() {
|
|
|
208
209
|
appType: "custom",
|
|
209
210
|
root: process.env.src_path,
|
|
210
211
|
})
|
|
212
|
+
|
|
213
|
+
// Expose Vite's resolved base to the SSR renderer so the URLs it injects
|
|
214
|
+
// (client entry, react-refresh preamble) match the path Vite serves under.
|
|
215
|
+
// Vite normalizes base with a trailing slash; trim it for clean URL joins.
|
|
216
|
+
process.env.APP_MOUNT_PATH = toMountPathPrefix(vite.config.base)
|
|
217
|
+
|
|
211
218
|
app.use(vite.middlewares)
|
|
212
219
|
}
|
|
213
220
|
|
|
@@ -30,7 +30,10 @@ export function Body(props) {
|
|
|
30
30
|
__html: `window.__SAFE_AREA_INITIAL__ = ${JSON.stringify(safeArea)}; window.__CATALYST_NATIVE_WEBVIEW__ = ${nativeWebView ? "true" : "false"}`,
|
|
31
31
|
}}
|
|
32
32
|
/>
|
|
33
|
-
{process.env.NODE_ENV === "development" &&
|
|
33
|
+
{process.env.NODE_ENV === "development" && (
|
|
34
|
+
// Base pinned to Vite's resolved base by server/expressServer.js.
|
|
35
|
+
<script type="module" src={`${process.env.APP_MOUNT_PATH || ""}/client/index.js`}></script>
|
|
36
|
+
)}
|
|
34
37
|
{jsx}
|
|
35
38
|
<script
|
|
36
39
|
/* eslint-disable */
|
|
@@ -6,8 +6,10 @@ const FastRefresh = () => {
|
|
|
6
6
|
type="module"
|
|
7
7
|
// eslint-disable-next-line risxss/catch-potential-xss-react
|
|
8
8
|
dangerouslySetInnerHTML={{
|
|
9
|
+
// Base-prefixed so the preamble resolves under a sub-path; otherwise
|
|
10
|
+
// plugin-react modules throw "$RefreshSig$ is not defined".
|
|
9
11
|
__html: `
|
|
10
|
-
import { injectIntoGlobalHook } from "/@react-refresh";
|
|
12
|
+
import { injectIntoGlobalHook } from "${process.env.APP_MOUNT_PATH || ""}/@react-refresh";
|
|
11
13
|
injectIntoGlobalHook(window);
|
|
12
14
|
window.$RefreshReg$ = () => {};
|
|
13
15
|
window.$RefreshSig$ = () => (type) => type;
|
|
@@ -5,6 +5,34 @@ import { pathToFileURL } from "url"
|
|
|
5
5
|
const emptyConfig = {
|
|
6
6
|
ssrPlugins: [],
|
|
7
7
|
clientPlugins: [],
|
|
8
|
+
/**
|
|
9
|
+
* devServer lets apps tune the Vite dev server without editing framework
|
|
10
|
+
* internals. All fields are optional and map 1-to-1 onto Vite's `server`
|
|
11
|
+
* config (https://vite.dev/config/server-options).
|
|
12
|
+
*
|
|
13
|
+
* The most common use-case is an app served under a sub-path behind an SSL
|
|
14
|
+
* reverse proxy (nginx/caddy):
|
|
15
|
+
*
|
|
16
|
+
* // buildConfig.js
|
|
17
|
+
* export default {
|
|
18
|
+
* devServer: {
|
|
19
|
+
* // Vite's base path — the single source of truth for the dev mount
|
|
20
|
+
* // path; must match the reverse-proxy location prefix. Defaults to "/".
|
|
21
|
+
* base: "/o-mweb",
|
|
22
|
+
*
|
|
23
|
+
* // HMR WebSocket tuning when the browser connects via the proxy
|
|
24
|
+
* hmr: {
|
|
25
|
+
* clientPort: 443, // port the browser uses (proxy's SSL port)
|
|
26
|
+
* path: "__vite_hmr" // WebSocket pathname (relative to base)
|
|
27
|
+
* },
|
|
28
|
+
*
|
|
29
|
+
* // Vite 6 rejects requests whose Host header isn't localhost/127.0.0.1.
|
|
30
|
+
* // Add your proxy hostname here so the dev server accepts them.
|
|
31
|
+
* allowedHosts: ["local.odinweb.1mg.com"],
|
|
32
|
+
* },
|
|
33
|
+
* }
|
|
34
|
+
*/
|
|
35
|
+
devServer: {},
|
|
8
36
|
}
|
|
9
37
|
|
|
10
38
|
export async function loadCustomViteConfig() {
|
|
@@ -308,9 +308,37 @@ function isValidExportName(name) {
|
|
|
308
308
|
// Loader-scoped require for discovering CJS exports
|
|
309
309
|
const loaderRequire = createRequire(import.meta.url)
|
|
310
310
|
|
|
311
|
-
const CJS_PATTERN = /\b(module\.exports\b|exports\.\w+\s*=)/
|
|
312
311
|
const REQUIRE_CALL_PATTERN = /\brequire\s*\(/
|
|
313
312
|
|
|
313
|
+
/**
|
|
314
|
+
* Decide whether a source file is really CommonJS by parsing it, not by
|
|
315
|
+
* regex-matching the raw text.
|
|
316
|
+
*
|
|
317
|
+
* A regex like /module\.exports\b/ cannot tell code from text, so any file that
|
|
318
|
+
* merely *mentions* module.exports inside a string, comment or template literal
|
|
319
|
+
* was misclassified as CJS. When such a file was real ESM with its own
|
|
320
|
+
* `export default`, the CJS shim appended a second one and Node failed the
|
|
321
|
+
* module with "Duplicate export of 'default'". Docs sites hit this constantly:
|
|
322
|
+
* a Markdown page documenting a CJS config compiles into a string literal in
|
|
323
|
+
* the bundled ESM output. Do not reintroduce source-regex detection.
|
|
324
|
+
*
|
|
325
|
+
* esbuild parses properly and lowers CJS itself, so a file it wraps in its
|
|
326
|
+
* __commonJS helper had no ESM syntax of its own — that is the CJS signal.
|
|
327
|
+
*/
|
|
328
|
+
function isCjsSource(source, filePath) {
|
|
329
|
+
try {
|
|
330
|
+
const { code } = transformSync(source, {
|
|
331
|
+
loader: "jsx",
|
|
332
|
+
format: "esm",
|
|
333
|
+
sourcefile: filePath,
|
|
334
|
+
target: "node20",
|
|
335
|
+
})
|
|
336
|
+
return /\bvar __commonJS =/.test(code)
|
|
337
|
+
} catch {
|
|
338
|
+
return false
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
314
342
|
// Shim __dirname and __filename for ESM app files (these globals only exist in CJS)
|
|
315
343
|
const createDirnameShim = (source) => {
|
|
316
344
|
const hasFilename = /\b(?:const|let|var)\s+__filename\b/.test(source)
|
|
@@ -396,7 +424,7 @@ export async function load(url, context, defaultLoad) {
|
|
|
396
424
|
// We can't use createRequire here because the file lives in a "type":"module"
|
|
397
425
|
// package — Node's CJS require refuses to load it. Instead, we wrap the
|
|
398
426
|
// source inline so that `module.exports` becomes the default export.
|
|
399
|
-
if (
|
|
427
|
+
if (isCjsSource(source, filePath)) {
|
|
400
428
|
const shimmed = [
|
|
401
429
|
createRequireShim(source),
|
|
402
430
|
createDirnameShim(source),
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Pure resolvers for the Vite dev-server config derived from an app's
|
|
2
|
+
// `buildConfig.devServer`. Side-effect free so the base precedence and the fs
|
|
3
|
+
// allowlist merge can be unit-tested without spinning up Vite.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Vite `base` for the dev server. `buildConfig.devServer.base` is the single
|
|
7
|
+
* source of truth (default "/"). Normalized to a leading slash and no trailing
|
|
8
|
+
* slash so it doubles as a URL prefix for the SSR renderer.
|
|
9
|
+
*/
|
|
10
|
+
export function resolveDevBase(devServer = {}) {
|
|
11
|
+
const base = devServer?.base
|
|
12
|
+
if (!base || base === "/") return "/"
|
|
13
|
+
return `/${String(base).trim().replace(/^\/+|\/+$/g, "")}`
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A resolved base as a URL prefix. Root ("/") becomes "" so
|
|
18
|
+
* `${prefix}/client/index.js` stays single-slashed.
|
|
19
|
+
*/
|
|
20
|
+
export function toMountPathPrefix(base) {
|
|
21
|
+
return !base || base === "/" ? "" : String(base).replace(/\/+$/, "")
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* fs.allow for the dev server. Framework paths are always present; apps may
|
|
26
|
+
* extend the list via `devServer.fs.allow` but cannot replace it or relax other
|
|
27
|
+
* fs guards (e.g. `strict`), so buildConfig can't widen filesystem exposure.
|
|
28
|
+
*/
|
|
29
|
+
export function resolveDevFsAllow(devFs, frameworkPaths) {
|
|
30
|
+
const extra = Array.isArray(devFs?.allow) ? devFs.allow : []
|
|
31
|
+
return [...frameworkPaths, ...extra]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Vite `server` block from `buildConfig.devServer`. Passthrough keys are spread
|
|
36
|
+
* first so the framework-owned `hmr` and `fs` always win.
|
|
37
|
+
*/
|
|
38
|
+
export function buildDevServer(devServer = {}, { frameworkPaths, isProduction = false } = {}) {
|
|
39
|
+
const { base, hmr, fs, ...serverOverrides } = devServer
|
|
40
|
+
return {
|
|
41
|
+
...serverOverrides,
|
|
42
|
+
hmr: isProduction ? false : (hmr ?? true),
|
|
43
|
+
fs: { allow: resolveDevFsAllow(fs, frameworkPaths) },
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import loadEnvironmentVariables from "../scripts/loadEnvironmentVariables.js"
|
|
2
2
|
loadEnvironmentVariables()
|
|
3
3
|
import { defineConfig } from "vite"
|
|
4
|
-
import baseConfig,
|
|
4
|
+
import { sharedViteConfig as baseConfig, getClientEnvVariables } from "./vite.config.js"
|
|
5
5
|
import path from "path"
|
|
6
6
|
import { manifestCategorizationPlugin } from "./manifest-categorization-plugin.js"
|
|
7
7
|
import { injectCacheKeyPlugin } from "./inject-cache-key-plugin.js"
|
package/dist/vite/vite.config.js
CHANGED
|
@@ -2,6 +2,8 @@ import { defineConfig, transformWithEsbuild } from "vite"
|
|
|
2
2
|
import react from "@vitejs/plugin-react"
|
|
3
3
|
import svgr from "vite-plugin-svgr"
|
|
4
4
|
import { builtinModules, createRequire } from "node:module"
|
|
5
|
+
import { loadCustomViteConfig } from "./loadCustomViteConfig.js"
|
|
6
|
+
import { resolveDevBase, buildDevServer } from "./resolveDevServerConfig.js"
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Treat all .scss imports as CSS modules (webpack compat).
|
|
@@ -362,7 +364,10 @@ export const isNodeOnlyExternal = (id) =>
|
|
|
362
364
|
id === "@grpc/grpc-js" ||
|
|
363
365
|
id.startsWith("@opentelemetry/")
|
|
364
366
|
|
|
365
|
-
|
|
367
|
+
// ─── Shared config ────────────────────────────────────────────────────────────
|
|
368
|
+
// Exported for the production build (vite.config.client.js spreads this in).
|
|
369
|
+
// Does NOT include `base` or `server` — those differ between dev and prod.
|
|
370
|
+
export const sharedViteConfig = {
|
|
366
371
|
// Parallel `vite build` (SSR + client) must use separate dirs or Vite will block on shared `node_modules/.vite`.
|
|
367
372
|
cacheDir: path.join(
|
|
368
373
|
process.env.src_path,
|
|
@@ -488,17 +493,34 @@ export default defineConfig({
|
|
|
488
493
|
"**/*.woff2",
|
|
489
494
|
],
|
|
490
495
|
|
|
491
|
-
// Server configuration
|
|
492
|
-
server: {
|
|
493
|
-
hmr: !isProduction,
|
|
494
|
-
fs: {
|
|
495
|
-
allow: [process.env.src_path, __dirname],
|
|
496
|
-
},
|
|
497
|
-
},
|
|
498
|
-
|
|
499
496
|
// Preview configuration for production preview
|
|
500
497
|
preview: {
|
|
501
498
|
port: process.env.NODE_SERVER_PORT ? parseInt(process.env.NODE_SERVER_PORT) : 3005,
|
|
502
499
|
host: process.env.NODE_SERVER_HOSTNAME || "localhost",
|
|
503
500
|
},
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// ─── Dev server config ────────────────────────────────────────────────────────
|
|
504
|
+
// Async factory so it can read the app's buildConfig.devServer for `base`, HMR
|
|
505
|
+
// and other Vite server options. `base` comes solely from devServer.base; the
|
|
506
|
+
// resolved value is propagated to the SSR renderer by server/expressServer.js.
|
|
507
|
+
// The production build (vite.config.client.js) ignores this and spreads
|
|
508
|
+
// sharedViteConfig directly.
|
|
509
|
+
export default defineConfig(async () => {
|
|
510
|
+
const { devServer = {}, ssrPlugins = [] } = await loadCustomViteConfig()
|
|
511
|
+
|
|
512
|
+
return {
|
|
513
|
+
...sharedViteConfig,
|
|
514
|
+
base: resolveDevBase(devServer),
|
|
515
|
+
server: buildDevServer(devServer, {
|
|
516
|
+
frameworkPaths: [process.env.src_path, __dirname],
|
|
517
|
+
isProduction,
|
|
518
|
+
}),
|
|
519
|
+
// Apply the app's SSR plugins in dev too — the production build already
|
|
520
|
+
// does this in vite.config.server.js. This lets buildConfig.ssrPlugins
|
|
521
|
+
// inject SSR-only config (e.g. a plugin whose `config()` hook adds
|
|
522
|
+
// ssr.noExternal to bundle React-consuming deps so dev SSR shares the
|
|
523
|
+
// app's single React instance) without hardcoding anything in the framework.
|
|
524
|
+
plugins: [...(sharedViteConfig.plugins || []), ...ssrPlugins],
|
|
525
|
+
}
|
|
504
526
|
})
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import loadEnvironmentVariables from "../scripts/loadEnvironmentVariables.js"
|
|
2
2
|
loadEnvironmentVariables()
|
|
3
3
|
import { defineConfig } from "vite"
|
|
4
|
-
|
|
4
|
+
// Spread the static shared config (a plain object), NOT the default export —
|
|
5
|
+
// the default export is now an async dev-server factory function, and spreading
|
|
6
|
+
// a function would silently drop cacheDir, resolve aliases, css, plugins and
|
|
7
|
+
// build from the production SSR bundle. Mirrors vite.config.client.js.
|
|
8
|
+
import { sharedViteConfig as baseConfig, getClientEnvVariables, isNodeOnlyExternal } from "./vite.config.js"
|
|
5
9
|
import path from "path"
|
|
6
10
|
import { fileURLToPath } from "url"
|
|
7
11
|
import { dirname } from "path"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "catalyst-core",
|
|
3
|
-
"version": "0.3.0-beta.
|
|
3
|
+
"version": "0.3.0-beta.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.jsx",
|
|
6
6
|
"description": "Web framework that provides great performance out of the box",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"scripts": {
|
|
31
31
|
"lint": "eslint .",
|
|
32
32
|
"lint-staged": "lint-staged",
|
|
33
|
+
"test:unit": "node --test \"test/**/*.test.js\"",
|
|
33
34
|
"prettify": "prettier . --write",
|
|
34
35
|
"prepare": "node ../../scripts/safe-rimraf.js ./dist && cp -r ./src ./dist && babel src/native --out-dir dist/native --config-file ./babel.native.config.cjs --ignore '**/.build/**' && babel src/sentry.js --out-file dist/sentry.cjs --config-file ./babel.native.config.cjs",
|
|
35
36
|
"prepublishOnly": "npm run prepare",
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { test } from "node:test"
|
|
2
|
+
import assert from "node:assert/strict"
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
resolveDevBase,
|
|
6
|
+
toMountPathPrefix,
|
|
7
|
+
resolveDevFsAllow,
|
|
8
|
+
buildDevServer,
|
|
9
|
+
} from "../../src/vite/resolveDevServerConfig.js"
|
|
10
|
+
|
|
11
|
+
// ─── resolveDevBase ───────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
test("resolveDevBase: resolves from devServer.base", () => {
|
|
14
|
+
assert.equal(resolveDevBase({ base: "/o-mweb" }), "/o-mweb")
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test("resolveDevBase: defaults to '/' when base is unset", () => {
|
|
18
|
+
assert.equal(resolveDevBase({}), "/")
|
|
19
|
+
assert.equal(resolveDevBase(undefined), "/")
|
|
20
|
+
assert.equal(resolveDevBase({ base: "/" }), "/")
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test("resolveDevBase: normalizes to a leading slash, no trailing slash", () => {
|
|
24
|
+
assert.equal(resolveDevBase({ base: "o-mweb" }), "/o-mweb")
|
|
25
|
+
assert.equal(resolveDevBase({ base: "/o-mweb/" }), "/o-mweb")
|
|
26
|
+
assert.equal(resolveDevBase({ base: " /o-mweb// " }), "/o-mweb")
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
// ─── toMountPathPrefix ────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
test("toMountPathPrefix: root maps to empty string for clean URL joins", () => {
|
|
32
|
+
assert.equal(toMountPathPrefix("/"), "")
|
|
33
|
+
assert.equal(toMountPathPrefix(""), "")
|
|
34
|
+
assert.equal(toMountPathPrefix(undefined), "")
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test("toMountPathPrefix: trims Vite's trailing slash", () => {
|
|
38
|
+
assert.equal(toMountPathPrefix("/o-mweb/"), "/o-mweb")
|
|
39
|
+
assert.equal(toMountPathPrefix("/o-mweb"), "/o-mweb")
|
|
40
|
+
// The joined result stays single-slashed.
|
|
41
|
+
assert.equal(`${toMountPathPrefix("/o-mweb/")}/client/index.js`, "/o-mweb/client/index.js")
|
|
42
|
+
assert.equal(`${toMountPathPrefix("/")}/client/index.js`, "/client/index.js")
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
// ─── resolveDevFsAllow: security-sensitive allowlist merge ─────────────────────
|
|
46
|
+
|
|
47
|
+
const FRAMEWORK = ["/app/src", "/framework/dist/vite"]
|
|
48
|
+
|
|
49
|
+
test("resolveDevFsAllow: framework paths always present, none provided", () => {
|
|
50
|
+
assert.deepEqual(resolveDevFsAllow(undefined, FRAMEWORK), FRAMEWORK)
|
|
51
|
+
assert.deepEqual(resolveDevFsAllow({}, FRAMEWORK), FRAMEWORK)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
test("resolveDevFsAllow: apps may EXTEND but never drop framework paths", () => {
|
|
55
|
+
const result = resolveDevFsAllow({ allow: ["/extra/pkg"] }, FRAMEWORK)
|
|
56
|
+
assert.deepEqual(result, ["/app/src", "/framework/dist/vite", "/extra/pkg"])
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test("resolveDevFsAllow: non-array allow is ignored (no widening via bad input)", () => {
|
|
60
|
+
assert.deepEqual(resolveDevFsAllow({ allow: "/" }, FRAMEWORK), FRAMEWORK)
|
|
61
|
+
assert.deepEqual(resolveDevFsAllow({ allow: null }, FRAMEWORK), FRAMEWORK)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
// ─── buildDevServer: precedence + security ────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
test("buildDevServer: hmr defaults to true in dev", () => {
|
|
67
|
+
const server = buildDevServer({}, { frameworkPaths: FRAMEWORK, isProduction: false })
|
|
68
|
+
assert.equal(server.hmr, true)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test("buildDevServer: hmr is false in production", () => {
|
|
72
|
+
const server = buildDevServer({ hmr: { clientPort: 443 } }, { frameworkPaths: FRAMEWORK, isProduction: true })
|
|
73
|
+
assert.equal(server.hmr, false)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
test("buildDevServer: app hmr overrides are honored in dev", () => {
|
|
77
|
+
const hmr = { clientPort: 443, path: "__vite_hmr" }
|
|
78
|
+
const server = buildDevServer({ hmr }, { frameworkPaths: FRAMEWORK, isProduction: false })
|
|
79
|
+
assert.deepEqual(server.hmr, hmr)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test("buildDevServer: passthrough keys (proxy/allowedHosts) are forwarded", () => {
|
|
83
|
+
const server = buildDevServer(
|
|
84
|
+
{ allowedHosts: ["local.example.com"], proxy: { "/api": "http://localhost:9000" } },
|
|
85
|
+
{ frameworkPaths: FRAMEWORK, isProduction: false }
|
|
86
|
+
)
|
|
87
|
+
assert.deepEqual(server.allowedHosts, ["local.example.com"])
|
|
88
|
+
assert.deepEqual(server.proxy, { "/api": "http://localhost:9000" })
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test("buildDevServer: app fs cannot replace the allowlist, only extend it", () => {
|
|
92
|
+
const server = buildDevServer(
|
|
93
|
+
{ fs: { allow: ["/extra"] } },
|
|
94
|
+
{ frameworkPaths: FRAMEWORK, isProduction: false }
|
|
95
|
+
)
|
|
96
|
+
assert.deepEqual(server.fs.allow, ["/app/src", "/framework/dist/vite", "/extra"])
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
test("buildDevServer: app cannot relax fs.strict or clobber fs via overrides", () => {
|
|
100
|
+
const server = buildDevServer(
|
|
101
|
+
{ fs: { allow: ["/"], strict: false } },
|
|
102
|
+
{ frameworkPaths: FRAMEWORK, isProduction: false }
|
|
103
|
+
)
|
|
104
|
+
// strict is dropped entirely (framework keeps Vite's secure default), and
|
|
105
|
+
// the framework paths remain — "/" is merely appended, not a replacement.
|
|
106
|
+
assert.equal(server.fs.strict, undefined)
|
|
107
|
+
assert.ok(server.fs.allow.includes("/app/src"))
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
test("buildDevServer: 'base' is not leaked into the server block", () => {
|
|
111
|
+
const server = buildDevServer({ base: "/o-mweb" }, { frameworkPaths: FRAMEWORK, isProduction: false })
|
|
112
|
+
assert.equal(server.base, undefined)
|
|
113
|
+
})
|