@greendrake/vite-preset 0.1.0 → 0.2.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.
- package/package.json +3 -3
- package/src/apiTarget.ts +5 -3
- package/src/html.ts +2 -1
- package/src/main.ts +17 -16
- package/src/sourceDeps.ts +6 -3
- package/src/staticRoots.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@greendrake/vite-preset",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Vite config factory and build-env helpers for Vue 3 single-page apps: plugin set, strict dev port, alias, dedupe and source-package pre-bundling rules",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Eugene Greendrake <eugene@greendrake.nz>",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"prettier": "@greendrake/dev-config/prettier",
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@greendrake/util": "0.
|
|
41
|
+
"@greendrake/util": "0.2.0",
|
|
42
42
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
43
43
|
"html-minifier-terser": "^7.2.0"
|
|
44
44
|
},
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"vite": ">=8"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@greendrake/dev-config": "0.
|
|
49
|
+
"@greendrake/dev-config": "0.2.0",
|
|
50
50
|
"@types/bun": "^1.3.5",
|
|
51
51
|
"@types/html-minifier-terser": "^7.0.2",
|
|
52
52
|
"@types/node": "^24.0.0",
|
package/src/apiTarget.ts
CHANGED
|
@@ -17,9 +17,11 @@
|
|
|
17
17
|
export interface ApiTargetEnv {
|
|
18
18
|
// True under `vite dev` (command === 'serve'); false in production builds.
|
|
19
19
|
dev: boolean
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
// Undefined as readily as absent: each is an environment variable, which
|
|
21
|
+
// is either set or not.
|
|
22
|
+
apiPort?: string | undefined
|
|
23
|
+
publicFeHost?: string | undefined
|
|
24
|
+
publicApiHost?: string | undefined
|
|
23
25
|
// Endpoint paths appended to the resolved origin (defaults /v1/api and
|
|
24
26
|
// /v1/ws). A backend that routes POST at the host root sets apiPath: ''.
|
|
25
27
|
apiPath?: string
|
package/src/html.ts
CHANGED
|
@@ -14,7 +14,8 @@ export const htmlPlaceholders = (map: Record<string, string>): Plugin => {
|
|
|
14
14
|
name: 'greendrake-html-placeholders',
|
|
15
15
|
transformIndexHtml: {
|
|
16
16
|
order: 'pre',
|
|
17
|
-
|
|
17
|
+
// The pattern is built from the map's own keys, so every match is one.
|
|
18
|
+
handler: html => html.replace(pattern, match => map[match]!)
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
}
|
package/src/main.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface VueSpaOptions {
|
|
|
23
23
|
// Compile-time globals; values are serialized automatically (strings become
|
|
24
24
|
// string literals, booleans become true/false, objects become object
|
|
25
25
|
// literals — e.g. the ApiTargetEnv carried by __API_TARGET_ENV__).
|
|
26
|
-
define?: Record<string, string | number | boolean | object | null | undefined>
|
|
26
|
+
define?: Record<string, string | number | boolean | object | null | undefined> | undefined
|
|
27
27
|
// Extra scss @use resolution roots (e.g. the app's src/scss).
|
|
28
28
|
scssLoadPaths?: string[]
|
|
29
29
|
// 'env' (default): the strict VITE_PORT convention, required when the dev
|
|
@@ -48,10 +48,10 @@ export interface VueSpaOptions {
|
|
|
48
48
|
// source-shipped by construction — an app with source packages of its own
|
|
49
49
|
// names them here, and must name the @greendrake scope again if it uses
|
|
50
50
|
// any.
|
|
51
|
-
sourcePackages?: string[]
|
|
51
|
+
sourcePackages?: string[] | undefined
|
|
52
52
|
// Deep-merged last over the preset — the escape hatch for anything
|
|
53
53
|
// app-specific (server.proxy, extra plugins, build tweaks).
|
|
54
|
-
overrides?: UserConfig
|
|
54
|
+
overrides?: UserConfig | undefined
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
// The libraries the app and every component package it renders must share one
|
|
@@ -89,11 +89,11 @@ export const vueSpa =
|
|
|
89
89
|
// none (and never serves) must not be made to produce one.
|
|
90
90
|
const portPin = command === 'serve' && options.port !== false ? { port: typeof options.port === 'number' ? options.port : requirePort(), strictPort: true } : undefined
|
|
91
91
|
const base: UserConfig = {
|
|
92
|
-
|
|
92
|
+
...(options.define && { define: Object.fromEntries(Object.entries(options.define).map(([key, value]) => [key, JSON.stringify(value)])) }),
|
|
93
93
|
plugins: [vue(), hmrCircularImportGuard(), ...(options.staticRoots?.length ? [staticRootsPlugin(options.staticRoots)] : []), ...(options.htmlPlaceholders ? [htmlPlaceholders(options.htmlPlaceholders)] : []), ...(options.htmlMinify ? [htmlMinify()] : [])],
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
...(command === 'serve'
|
|
95
|
+
? {
|
|
96
|
+
server: {
|
|
97
97
|
...portPin,
|
|
98
98
|
// '..' reaches the workspace an app sits directly
|
|
99
99
|
// inside. Anything the dev server must read from
|
|
@@ -104,10 +104,11 @@ export const vueSpa =
|
|
|
104
104
|
// refused.
|
|
105
105
|
fs: { allow: ['..', ...(options.staticRoots ?? []).map(root => root.dir)] }
|
|
106
106
|
}
|
|
107
|
-
|
|
107
|
+
}
|
|
108
|
+
: {}),
|
|
108
109
|
// vite preview also loads with command 'serve'; pin it to the same
|
|
109
110
|
// port convention so E2E runs are deterministic.
|
|
110
|
-
preview: portPin,
|
|
111
|
+
...(portPin && { preview: portPin }),
|
|
111
112
|
resolve: {
|
|
112
113
|
alias: { '@': path.resolve(options.dirname, './src') },
|
|
113
114
|
dedupe: FRAMEWORK
|
|
@@ -131,13 +132,13 @@ export const vueSpa =
|
|
|
131
132
|
exclude: allDeps.filter(isSourcePackage),
|
|
132
133
|
include: [...new Set([...FRAMEWORK.filter(name => allDeps.includes(name)), ...nestedDependencies(options.dirname, deps, isSourcePackage)])]
|
|
133
134
|
},
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
135
|
+
...(options.scssLoadPaths && {
|
|
136
|
+
css: {
|
|
137
|
+
preprocessorOptions: {
|
|
138
|
+
scss: { loadPaths: options.scssLoadPaths }
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}),
|
|
141
142
|
build: {
|
|
142
143
|
rolldownOptions: {
|
|
143
144
|
output: {
|
package/src/sourceDeps.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
1
|
+
import { existsSync, readFileSync, realpathSync } from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
|
|
4
4
|
// The parts of a package.json this walk reads.
|
|
@@ -16,11 +16,14 @@ export interface DeclaredDependencies {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
// Where the installer put a package: the nearest node_modules at or above
|
|
19
|
-
// `from` holding it.
|
|
19
|
+
// `from` holding it, as the real path behind whatever link reached it. That is
|
|
20
|
+
// where its own dependencies are found from — an isolated install (bun's, pnpm's)
|
|
21
|
+
// puts them beside the package's real directory, not beside the link an app's
|
|
22
|
+
// node_modules holds — and it is what Node and Vite resolve from too.
|
|
20
23
|
const packageDir = (from: string, name: string): string => {
|
|
21
24
|
for (let dir = from; ; dir = path.dirname(dir)) {
|
|
22
25
|
const candidate = path.join(dir, 'node_modules', name)
|
|
23
|
-
if (existsSync(path.join(candidate, 'package.json'))) return candidate
|
|
26
|
+
if (existsSync(path.join(candidate, 'package.json'))) return realpathSync(candidate)
|
|
24
27
|
if (path.dirname(dir) === dir) throw new Error(`${name} is declared but not installed anywhere above ${from}`)
|
|
25
28
|
}
|
|
26
29
|
}
|
package/src/staticRoots.ts
CHANGED
|
@@ -42,7 +42,7 @@ export const staticRoots = (roots: StaticRoot[]): Plugin => ({
|
|
|
42
42
|
|
|
43
43
|
configureServer(server) {
|
|
44
44
|
server.middlewares.use((req, res, next) => {
|
|
45
|
-
const url = (req.url ?? '').
|
|
45
|
+
const url = (req.url ?? '').replace(/\?.*/, '')
|
|
46
46
|
const root = roots.find(r => url.startsWith(`${r.urlPath}/`))
|
|
47
47
|
if (!root) {
|
|
48
48
|
next()
|