vxrn 0.1.84 → 0.1.85

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.
Files changed (36) hide show
  1. package/LICENSE +22 -0
  2. package/dist/cjs/exports/build.js +4 -3
  3. package/dist/cjs/exports/build.js.map +1 -1
  4. package/dist/cjs/exports/build.native.js +6 -3
  5. package/dist/cjs/exports/build.native.js.map +1 -1
  6. package/dist/cjs/utils/findDepsToOptimize.js +167 -0
  7. package/dist/cjs/utils/findDepsToOptimize.js.map +6 -0
  8. package/dist/cjs/utils/findDepsToOptimize.native.js +564 -0
  9. package/dist/cjs/utils/findDepsToOptimize.native.js.map +6 -0
  10. package/dist/cjs/utils/getBaseViteConfig.js +2 -0
  11. package/dist/cjs/utils/getBaseViteConfig.js.map +1 -1
  12. package/dist/cjs/utils/getBaseViteConfig.native.js +2 -0
  13. package/dist/cjs/utils/getBaseViteConfig.native.js.map +1 -1
  14. package/dist/esm/exports/build.js +4 -3
  15. package/dist/esm/exports/build.js.map +1 -1
  16. package/dist/esm/exports/build.mjs +4 -3
  17. package/dist/esm/exports/build.native.js +6 -3
  18. package/dist/esm/exports/build.native.js.map +1 -1
  19. package/dist/esm/utils/findDepsToOptimize.js +145 -0
  20. package/dist/esm/utils/findDepsToOptimize.js.map +6 -0
  21. package/dist/esm/utils/findDepsToOptimize.mjs +130 -0
  22. package/dist/esm/utils/findDepsToOptimize.native.js +530 -0
  23. package/dist/esm/utils/findDepsToOptimize.native.js.map +6 -0
  24. package/dist/esm/utils/getBaseViteConfig.js +2 -0
  25. package/dist/esm/utils/getBaseViteConfig.js.map +1 -1
  26. package/dist/esm/utils/getBaseViteConfig.mjs +1 -1
  27. package/dist/esm/utils/getBaseViteConfig.native.js +2 -0
  28. package/dist/esm/utils/getBaseViteConfig.native.js.map +1 -1
  29. package/package.json +5 -5
  30. package/src/exports/build.ts +3 -2
  31. package/src/types.ts +2 -3
  32. package/src/utils/findDepsToOptimize.ts +293 -0
  33. package/src/utils/getBaseViteConfig.ts +2 -0
  34. package/types/types.d.ts +2 -3
  35. package/types/utils/findDepsToOptimize.d.ts +19 -0
  36. package/types/utils/getOptionsFilled.d.ts +1 -0
@@ -0,0 +1,293 @@
1
+ // forked from https://github.com/svitejs/vitefu/blob/main/src/index.js
2
+
3
+ import fs from 'node:fs/promises'
4
+ import fsSync from 'node:fs'
5
+ import path from 'node:path'
6
+
7
+ // let pnp
8
+ // if (process.versions.pnp) {
9
+ // try {
10
+ // const { createRequire } = (await import('node:module')).default
11
+ // pnp = createRequire(import.meta.url)('pnpapi')
12
+ // } catch {}
13
+ // }
14
+
15
+ export { isDepIncluded, isDepExcluded, isDepNoExternaled, isDepExternaled }
16
+
17
+ export async function crawlFrameworkPkgs(options) {
18
+ const pkgJsonPath = await findClosestPkgJsonPath(options.root)
19
+ if (!pkgJsonPath) {
20
+ // @ts-expect-error don't throw in deno as package.json is not required
21
+ if (typeof Deno !== 'undefined') {
22
+ return {
23
+ optimizeDeps: { include: [], exclude: [] },
24
+ ssr: { noExternal: [], external: [] },
25
+ }
26
+ }
27
+ throw new Error(`Cannot find package.json from ${options.root}`)
28
+ }
29
+ const pkgJson = await readJson(pkgJsonPath).catch((e) => {
30
+ throw new Error(`Unable to read ${pkgJsonPath}`, { cause: e })
31
+ })
32
+
33
+ let optimizeDepsInclude: string[] = []
34
+ let optimizeDepsExclude: string[] = []
35
+ let ssrNoExternal: string[] = []
36
+ let ssrExternal: string[] = []
37
+
38
+ await crawl(pkgJsonPath, pkgJson)
39
+
40
+ // respect vite user config
41
+ if (options.viteUserConfig) {
42
+ // remove includes that are explicitly excluded in optimizeDeps
43
+ const _optimizeDepsExclude = options.viteUserConfig?.optimizeDeps?.exclude
44
+ if (_optimizeDepsExclude) {
45
+ optimizeDepsInclude = optimizeDepsInclude.filter(
46
+ (dep) => !isDepExcluded(dep, _optimizeDepsExclude)
47
+ )
48
+ }
49
+ // remove excludes that are explicitly included in optimizeDeps
50
+ const _optimizeDepsInclude = options.viteUserConfig?.optimizeDeps?.include
51
+ if (_optimizeDepsInclude) {
52
+ optimizeDepsExclude = optimizeDepsExclude.filter(
53
+ (dep) => !isDepIncluded(dep, _optimizeDepsInclude)
54
+ )
55
+ }
56
+ // remove noExternals that are explicitly externalized
57
+ const _ssrExternal = options.viteUserConfig?.ssr?.external
58
+ if (_ssrExternal) {
59
+ ssrNoExternal = ssrNoExternal.filter((dep) => !isDepExternaled(dep, _ssrExternal))
60
+ }
61
+ // remove externals that are explicitly noExternal
62
+ const _ssrNoExternal = options.viteUserConfig?.ssr?.noExternal
63
+ if (_ssrNoExternal) {
64
+ ssrExternal = ssrExternal.filter((dep) => !isDepNoExternaled(dep, _ssrNoExternal))
65
+ }
66
+ }
67
+
68
+ return {
69
+ optimizeDeps: {
70
+ include: optimizeDepsInclude,
71
+ exclude: optimizeDepsExclude,
72
+ },
73
+ ssr: {
74
+ noExternal: ssrNoExternal,
75
+ external: ssrExternal,
76
+ },
77
+ }
78
+
79
+ /**
80
+ * crawl the package.json dependencies for framework packages. rules:
81
+ * 1. a framework package should be `optimizeDeps.exclude` and `ssr.noExternal`.
82
+ * 2. the deps of the framework package should be `optimizeDeps.include` and `ssr.external`
83
+ * unless the dep is also a framework package, in which case do no1 & no2 recursively.
84
+ * 3. any non-framework packages that aren't imported by a framework package can be skipped entirely.
85
+ * 4. a semi-framework package is like a framework package, except it isn't `optimizeDeps.exclude`,
86
+ * but only applies `ssr.noExternal`.
87
+ * @param {string} pkgJsonPath
88
+ * @param {Record<string, any>} pkgJson
89
+ * @param {string[]} [parentDepNames]
90
+ */
91
+ async function crawl(
92
+ pkgJsonPath: string,
93
+ pkgJson: Record<string, any>,
94
+ parentDepNames: string[] = []
95
+ ) {
96
+ const isRoot = parentDepNames.length === 0
97
+
98
+ let deps = [
99
+ ...Object.keys(pkgJson.dependencies || {}),
100
+ ...(isRoot ? Object.keys(pkgJson.devDependencies || {}) : []),
101
+ ]
102
+
103
+ deps = deps.filter((dep) => {
104
+ // skip circular deps
105
+ if (parentDepNames.includes(dep)) {
106
+ return false
107
+ }
108
+
109
+ const isFrameworkPkg = options.isFrameworkPkgByName?.(dep)
110
+ const isSemiFrameworkPkg = options.isSemiFrameworkPkgByName?.(dep)
111
+ if (isFrameworkPkg) {
112
+ // framework packages should be excluded from optimization as esbuild can't handle them.
113
+ // otherwise it'll cause https://github.com/vitejs/vite/issues/3910
114
+ optimizeDepsExclude.push(dep)
115
+ // framework packages should be noExternal so that they go through vite's transformation
116
+ // pipeline, since nodejs can't support them.
117
+ ssrNoExternal.push(dep)
118
+ } else if (isSemiFrameworkPkg) {
119
+ // semi-framework packages should do the same except for optimization exclude as they
120
+ // aren't needed to work (they don't contain raw framework components)
121
+ ssrNoExternal.push(dep)
122
+ }
123
+
124
+ // only those that are explictly false can skip crawling since we don't need to do anything
125
+ // special for them
126
+ if (isFrameworkPkg === false || isSemiFrameworkPkg === false) {
127
+ return false
128
+ }
129
+ // if `true`, we need to crawl the nested deps to deep include and ssr externalize them in dev.
130
+ // if `undefined`, it's the same as "i don't know". we need to crawl and find the package.json
131
+ // to find out.
132
+ return true
133
+ })
134
+
135
+ const promises = deps.map(async (dep) => {
136
+ const depPkgJsonPath = await findDepPkgJsonPath(dep, pkgJsonPath)
137
+ if (!depPkgJsonPath) return
138
+ const depPkgJson = await readJson(depPkgJsonPath).catch(() => {})
139
+ if (!depPkgJson) return
140
+
141
+ // fast path if this dep is already a framework dep based on the filter condition above
142
+ const cachedIsFrameworkPkg = ssrNoExternal.includes(dep)
143
+ if (cachedIsFrameworkPkg) {
144
+ return crawl(depPkgJsonPath, depPkgJson, parentDepNames.concat(dep))
145
+ }
146
+
147
+ // check if this dep is a framework dep, if so, track and crawl it
148
+ const isFrameworkPkg = options.isFrameworkPkgByJson?.(depPkgJson)
149
+ const isSemiFrameworkPkg = options.isSemiFrameworkPkgByJson?.(depPkgJson)
150
+ if (isFrameworkPkg || isSemiFrameworkPkg) {
151
+ // see explanation in filter condition above
152
+ if (isFrameworkPkg) {
153
+ optimizeDepsExclude.push(dep)
154
+ ssrNoExternal.push(dep)
155
+ } else if (isSemiFrameworkPkg) {
156
+ ssrNoExternal.push(dep)
157
+ }
158
+ return crawl(depPkgJsonPath, depPkgJson, parentDepNames.concat(dep))
159
+ }
160
+
161
+ // if we're crawling in a non-root state, the parent is 100% a framework package
162
+ // because of the above if block. in this case, if it's dep of a non-framework
163
+ // package, handle special cases for them.
164
+ if (!isRoot) {
165
+ // deep include it if it's a CJS package, so it becomes ESM and vite is happy.
166
+ if (await pkgNeedsOptimization(depPkgJson, depPkgJsonPath)) {
167
+ optimizeDepsInclude.push(parentDepNames.concat(dep).join(' > '))
168
+ }
169
+ // also externalize it in dev so it doesn't trip vite's SSR transformation.
170
+ // we do in dev only as build cannot access deep external packages in strict
171
+ // dependency installations, such as pnpm.
172
+ if (!options.isBuild && !ssrExternal.includes(dep)) {
173
+ ssrExternal.push(dep)
174
+ }
175
+ }
176
+ })
177
+
178
+ await Promise.all(promises)
179
+ }
180
+ }
181
+
182
+ export async function findDepPkgJsonPath(dep, parent) {
183
+ // if (pnp) {
184
+ // try {
185
+ // const depRoot = pnp.resolveToUnqualified(dep, parent)
186
+ // if (!depRoot) return
187
+ // return path.join(depRoot, 'package.json')
188
+ // } catch {
189
+ // return
190
+ // }
191
+ // }
192
+
193
+ let root = parent
194
+ while (root) {
195
+ const pkg = path.join(root, 'node_modules', dep, 'package.json')
196
+ try {
197
+ await fs.access(pkg)
198
+ // use 'node:fs' version to match 'vite:resolve' and avoid realpath.native quirk
199
+ // https://github.com/sveltejs/vite-plugin-svelte/issues/525#issuecomment-1355551264
200
+ return fsSync.realpathSync(pkg)
201
+ } catch {}
202
+ const nextRoot = path.dirname(root)
203
+ if (nextRoot === root) break
204
+ root = nextRoot
205
+ }
206
+ }
207
+
208
+ export async function findClosestPkgJsonPath(dir: string, predicate?: Function) {
209
+ if (dir.endsWith('package.json')) {
210
+ dir = path.dirname(dir)
211
+ }
212
+ while (dir) {
213
+ const pkg = path.join(dir, 'package.json')
214
+ try {
215
+ const stat = await fs.stat(pkg)
216
+ if (stat.isFile() && (!predicate || (await predicate(pkg)))) {
217
+ return pkg
218
+ }
219
+ } catch {}
220
+ const nextDir = path.dirname(dir)
221
+ if (nextDir === dir) break
222
+ dir = nextDir
223
+ }
224
+ }
225
+
226
+ export async function pkgNeedsOptimization(pkgJson: any, pkgJsonPath: string) {
227
+ // only optimize if is cjs, using the below as heuristic
228
+ // see https://github.com/sveltejs/vite-plugin-svelte/issues/162
229
+ if (pkgJson.module || pkgJson.exports) return false
230
+ // if have main, ensure entry is js so vite can prebundle it
231
+ // see https://github.com/sveltejs/vite-plugin-svelte/issues/233
232
+ if (pkgJson.main) {
233
+ const entryExt = path.extname(pkgJson.main)
234
+ return !entryExt || entryExt === '.js' || entryExt === '.cjs'
235
+ }
236
+ // check if has implicit index.js entrypoint to prebundle
237
+ // see https://github.com/sveltejs/vite-plugin-svelte/issues/281
238
+ // see https://github.com/solidjs/vite-plugin-solid/issues/70#issuecomment-1306488154
239
+ try {
240
+ await fs.access(path.join(path.dirname(pkgJsonPath), 'index.js'))
241
+ return true
242
+ } catch {
243
+ return false
244
+ }
245
+ }
246
+
247
+ async function readJson(findDepPkgJsonPath) {
248
+ return JSON.parse(await fs.readFile(findDepPkgJsonPath, 'utf8'))
249
+ }
250
+
251
+ function isDepIncluded(dep, optimizeDepsInclude) {
252
+ return optimizeDepsInclude.some((id) => parseIncludeStr(id) === dep)
253
+ }
254
+
255
+ function isDepExcluded(dep, optimizeDepsExclude) {
256
+ dep = parseIncludeStr(dep)
257
+ return optimizeDepsExclude.some((id) => id === dep || dep.startsWith(`${id}/`))
258
+ }
259
+
260
+ function isDepNoExternaled(dep, ssrNoExternal) {
261
+ if (ssrNoExternal === true) {
262
+ return true
263
+ }
264
+ return isMatch(dep, ssrNoExternal)
265
+ }
266
+
267
+ function isDepExternaled(dep, ssrExternal) {
268
+ return ssrExternal.includes(dep)
269
+ }
270
+
271
+ /**
272
+ * @param {string} raw could be "foo" or "foo > bar" etc
273
+ */
274
+ function parseIncludeStr(raw) {
275
+ const lastArrow = raw.lastIndexOf('>')
276
+ return lastArrow === -1 ? raw : raw.slice(lastArrow + 1).trim()
277
+ }
278
+
279
+ /**
280
+ * @param {string} target
281
+ * @param {string | RegExp | (string | RegExp)[]} pattern
282
+ */
283
+ function isMatch(target, pattern) {
284
+ if (Array.isArray(pattern)) {
285
+ return pattern.some((p) => isMatch(target, p))
286
+ }
287
+ if (typeof pattern === 'string') {
288
+ return target === pattern
289
+ }
290
+ if (pattern instanceof RegExp) {
291
+ return pattern.test(target)
292
+ }
293
+ }
@@ -22,6 +22,8 @@ export function getBaseViteConfig({ mode }: { mode: 'development' | 'production'
22
22
 
23
23
  // TODO auto dedupe all include optimize deps?
24
24
  dedupe: [
25
+ 'vxs',
26
+ '@vxrn/safe-area',
25
27
  'react',
26
28
  'react-dom',
27
29
  'react-dom/client',
package/types/types.d.ts CHANGED
@@ -29,15 +29,14 @@ export type ClientManifestEntry = {
29
29
  };
30
30
  export type VXRNConfig = {
31
31
  /**
32
- * The entry points to your app. For web, it uses your `root` and looks for an index.html
32
+ * The entry points to your app. For web, it defaults to using your `root` to look for an index.html
33
33
  *
34
34
  * Defaults:
35
35
  * native: ./src/entry-native.tsx
36
- * server: ./src/entry-server.tsx
37
36
  */
38
37
  entries?: {
39
38
  native?: string;
40
- server?: string;
39
+ web?: string;
41
40
  };
42
41
  root?: string;
43
42
  host?: string;
@@ -0,0 +1,19 @@
1
+ export { isDepIncluded, isDepExcluded, isDepNoExternaled, isDepExternaled };
2
+ export declare function crawlFrameworkPkgs(options: any): Promise<{
3
+ optimizeDeps: {
4
+ include: string[];
5
+ exclude: string[];
6
+ };
7
+ ssr: {
8
+ noExternal: string[];
9
+ external: string[];
10
+ };
11
+ }>;
12
+ export declare function findDepPkgJsonPath(dep: any, parent: any): Promise<string | undefined>;
13
+ export declare function findClosestPkgJsonPath(dir: string, predicate?: Function): Promise<string | undefined>;
14
+ export declare function pkgNeedsOptimization(pkgJson: any, pkgJsonPath: string): Promise<boolean>;
15
+ declare function isDepIncluded(dep: any, optimizeDepsInclude: any): any;
16
+ declare function isDepExcluded(dep: any, optimizeDepsExclude: any): any;
17
+ declare function isDepNoExternaled(dep: any, ssrNoExternal: any): any;
18
+ declare function isDepExternaled(dep: any, ssrExternal: any): any;
19
+ //# sourceMappingURL=findDepsToOptimize.d.ts.map
@@ -5,6 +5,7 @@ export declare function getOptionsFilled(options: VXRNConfig, internal?: {
5
5
  }): Promise<{
6
6
  entries: {
7
7
  native: string;
8
+ web?: string | undefined;
8
9
  server: string;
9
10
  };
10
11
  packageJSON: import("pkg-types").PackageJson;