zyzz 0.0.7 → 0.0.9

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 (78) hide show
  1. package/README.md +7 -7
  2. package/dist/Style.d.ts +2 -2
  3. package/dist/Style.d.ts.map +1 -1
  4. package/dist/Style.js +4 -4
  5. package/dist/Style.js.map +1 -1
  6. package/dist/babel/index.d.ts +4 -1
  7. package/dist/babel/index.d.ts.map +1 -1
  8. package/dist/babel/index.js +6 -3
  9. package/dist/babel/index.js.map +1 -1
  10. package/dist/babel/internal/Compilation.d.ts +12 -0
  11. package/dist/babel/internal/Compilation.d.ts.map +1 -0
  12. package/dist/babel/internal/Compilation.js +3 -0
  13. package/dist/babel/internal/Compilation.js.map +1 -0
  14. package/dist/compiler/Graph.d.ts +6 -1
  15. package/dist/compiler/Graph.d.ts.map +1 -1
  16. package/dist/compiler/Graph.js +160 -36
  17. package/dist/compiler/Graph.js.map +1 -1
  18. package/dist/compiler/Transform.d.ts.map +1 -1
  19. package/dist/compiler/Transform.js +2 -1
  20. package/dist/compiler/Transform.js.map +1 -1
  21. package/dist/compiler/internal/Stylesheets.d.ts +8 -0
  22. package/dist/compiler/internal/Stylesheets.d.ts.map +1 -1
  23. package/dist/compiler/internal/Stylesheets.js +4 -0
  24. package/dist/compiler/internal/Stylesheets.js.map +1 -1
  25. package/dist/internal/Value.d.ts +5 -5
  26. package/dist/internal/Value.d.ts.map +1 -1
  27. package/dist/internal/Value.js +18 -64
  28. package/dist/internal/Value.js.map +1 -1
  29. package/dist/metro/Graph.d.ts +9 -1
  30. package/dist/metro/Graph.d.ts.map +1 -1
  31. package/dist/metro/Graph.js +5 -4
  32. package/dist/metro/Graph.js.map +1 -1
  33. package/dist/metro/transformer.d.ts +0 -1
  34. package/dist/metro/transformer.d.ts.map +1 -1
  35. package/dist/metro/transformer.js +19 -1
  36. package/dist/metro/transformer.js.map +1 -1
  37. package/dist/next/index.d.ts +3 -3
  38. package/dist/next/index.d.ts.map +1 -1
  39. package/dist/next/index.js +25 -30
  40. package/dist/next/index.js.map +1 -1
  41. package/dist/next/internal/Project.d.ts +4 -4
  42. package/dist/next/internal/Project.d.ts.map +1 -1
  43. package/dist/next/internal/Project.js +153 -107
  44. package/dist/next/internal/Project.js.map +1 -1
  45. package/dist/next/loader.d.ts +3 -1
  46. package/dist/next/loader.d.ts.map +1 -1
  47. package/dist/next/loader.js +152 -99
  48. package/dist/next/loader.js.map +1 -1
  49. package/dist/node/Host.d.ts.map +1 -1
  50. package/dist/node/Host.js +11 -3
  51. package/dist/node/Host.js.map +1 -1
  52. package/dist/node/internal/Snapshot.d.ts +12 -0
  53. package/dist/node/internal/Snapshot.d.ts.map +1 -0
  54. package/dist/node/internal/Snapshot.js +74 -0
  55. package/dist/node/internal/Snapshot.js.map +1 -0
  56. package/dist/unplugin/index.d.ts.map +1 -1
  57. package/dist/unplugin/index.js +13 -9
  58. package/dist/unplugin/index.js.map +1 -1
  59. package/dist/vite/index.d.ts.map +1 -1
  60. package/dist/vite/index.js +130 -27
  61. package/dist/vite/index.js.map +1 -1
  62. package/package.json +1 -1
  63. package/src/Style.ts +6 -6
  64. package/src/babel/index.ts +10 -4
  65. package/src/babel/internal/Compilation.ts +13 -0
  66. package/src/compiler/Graph.ts +213 -47
  67. package/src/compiler/Transform.ts +2 -1
  68. package/src/compiler/internal/Stylesheets.ts +9 -0
  69. package/src/internal/Value.ts +40 -88
  70. package/src/metro/Graph.ts +5 -3
  71. package/src/metro/transformer.ts +26 -1
  72. package/src/next/index.ts +26 -31
  73. package/src/next/internal/Project.ts +196 -155
  74. package/src/next/loader.ts +181 -124
  75. package/src/node/Host.ts +15 -3
  76. package/src/node/internal/Snapshot.ts +79 -0
  77. package/src/unplugin/index.ts +12 -8
  78. package/src/vite/index.ts +161 -35
package/src/vite/index.ts CHANGED
@@ -14,6 +14,8 @@ import * as Reset from '../node/Reset.js'
14
14
  import { isBuiltin } from 'node:module'
15
15
  import * as Parser from 'oxc-parser'
16
16
  import * as Walker from 'oxc-walker'
17
+ import * as Snapshot from '../node/internal/Snapshot.js'
18
+ import * as Syntax from '../compiler/internal/Syntax.js'
17
19
  import * as Scope from '../compiler/internal/Scope.js'
18
20
  import type { Environment, Plugin, Rollup, ViteDevServer } from 'vite'
19
21
  import * as Graph from '../compiler/Graph.js'
@@ -40,7 +42,23 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
40
42
  if (native && options.compiler === false)
41
43
  throw new Error('Native builds require source compilation.')
42
44
 
45
+ const snapshots = new WeakMap<
46
+ Environment,
47
+ ReturnType<typeof Snapshot.create>
48
+ >()
43
49
  const states = new WeakMap<Environment, Map<string, Entry>>()
50
+ const removed = new WeakMap<Environment, Set<string>>()
51
+ const reads = new WeakMap<Environment, Map<string, string>>()
52
+ const compilers = new WeakMap<Environment, Graph.create.ReturnType>()
53
+
54
+ function compiler(environment: Environment) {
55
+ let value = compilers.get(environment)
56
+ if (!value) {
57
+ value = Graph.create()
58
+ compilers.set(environment, value)
59
+ }
60
+ return value
61
+ }
44
62
  const discoveries = new WeakMap<Environment, Promise<Map<string, string>>>()
45
63
  const contributionFiles = new WeakMap<Environment, Set<string>>()
46
64
  const assets = new Map<string, string>()
@@ -49,8 +67,19 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
49
67
  const graphs = new Map<string, ReadonlySet<string>>()
50
68
  const initializers = new WeakMap<Environment, Entry>()
51
69
  const sourceEntrypoints = new Set<string>()
70
+ const identities = new Map<string, string>()
71
+ const lazyImports = new WeakMap<Parser.ParseResult, string[]>()
52
72
  let root: string
53
73
 
74
+ function snapshot(environment: Environment) {
75
+ let value = snapshots.get(environment)
76
+ if (!value) {
77
+ value = Snapshot.create()
78
+ snapshots.set(environment, value)
79
+ }
80
+ return value
81
+ }
82
+
54
83
  function entries(environment: Environment) {
55
84
  let state = states.get(environment)
56
85
 
@@ -63,7 +92,12 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
63
92
  }
64
93
 
65
94
  function sourceId(file: string) {
66
- return `app/${Path.relative(root, file).split(Path.sep).join('/')}`
95
+ let id = identities.get(file)
96
+ if (!id) {
97
+ id = `app/${Path.relative(root, file).split(Path.sep).join('/')}`
98
+ identities.set(file, id)
99
+ }
100
+ return id
67
101
  }
68
102
 
69
103
  function resource(id: string) {
@@ -273,7 +307,20 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
273
307
  file: string,
274
308
  event: string,
275
309
  ) {
276
- if (event === 'delete') entries(environment).delete(file)
310
+ reads.delete(environment)
311
+ if (event === 'delete') {
312
+ if (entries(environment).has(file)) {
313
+ let files = removed.get(environment)
314
+ if (!files) {
315
+ files = new Set()
316
+ removed.set(environment, files)
317
+ }
318
+ files.add(file)
319
+ }
320
+ entries(environment).delete(file)
321
+ snapshot(environment).delete(file, sourceId(file))
322
+ identities.delete(file)
323
+ }
277
324
 
278
325
  const pending = discoveries.get(environment)
279
326
  if (!pending || !eager(file)) return
@@ -330,7 +377,17 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
330
377
  host.watch(file)
331
378
 
332
379
  const id = sourceId(file)
333
- const text = source ?? (await Fs.readFile(file, 'utf8'))
380
+ let cached = reads.get(entry.environment)
381
+ if (!cached) {
382
+ cached = new Map()
383
+ reads.set(entry.environment, cached)
384
+ }
385
+ // Full-project compilation must not reuse reads from concurrent module transforms.
386
+ const text =
387
+ source ??
388
+ (everything ? undefined : cached.get(file)) ??
389
+ (await snapshot(entry.environment).read(file))
390
+ if (!everything) cached.set(file, text)
334
391
 
335
392
  modules[id] = text
336
393
 
@@ -338,8 +395,9 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
338
395
 
339
396
  imports[id] = resolutions
340
397
 
341
- const parsed = Parser.parseSync('source.tsx', text, {
342
- sourceType: 'module',
398
+ const parsed = snapshot(entry.environment).parse({
399
+ moduleId: id,
400
+ source: text,
343
401
  })
344
402
 
345
403
  for (const node of parsed.program.body) {
@@ -433,18 +491,22 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
433
491
  }
434
492
 
435
493
  // Lazy imports stay outside this compile but scope the documents that load them.
436
- const specifiers: string[] = []
437
-
438
- Walker.walk(parsed.program, {
439
- enter(node) {
440
- if (
441
- node.type === 'ImportExpression' &&
442
- node.source.type === 'Literal' &&
443
- typeof node.source.value === 'string'
444
- )
445
- specifiers.push(node.source.value)
446
- },
447
- })
494
+ let specifiers = lazyImports.get(parsed)
495
+ if (!specifiers) {
496
+ specifiers = []
497
+ const collected = specifiers
498
+ Walker.walk(parsed.program, {
499
+ enter(node) {
500
+ if (
501
+ node.type === 'ImportExpression' &&
502
+ node.source.type === 'Literal' &&
503
+ typeof node.source.value === 'string'
504
+ )
505
+ collected.push(node.source.value)
506
+ },
507
+ })
508
+ lazyImports.set(parsed, specifiers)
509
+ }
448
510
 
449
511
  const targets = new Set<string>()
450
512
 
@@ -471,8 +533,9 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
471
533
  const selected = contributionFiles.get(entry.environment)?.has(file)
472
534
 
473
535
  if (allSources) {
474
- const { program } = Parser.parseSync('source.tsx', source, {
475
- sourceType: 'module',
536
+ const { program } = snapshot(entry.environment).parse({
537
+ moduleId: sourceId(file),
538
+ source,
476
539
  })
477
540
  const dynamic: import('@oxc-project/types').ImportExpression[] = []
478
541
 
@@ -642,6 +705,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
642
705
  )
643
706
 
644
707
  const result = entry.compiler.compile({
708
+ [Syntax.cache]: snapshot(entry.environment).programs(modules),
645
709
  compiler: options.compiler,
646
710
  reset: options.reset ? Reset.read() : undefined,
647
711
  native,
@@ -656,6 +720,8 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
656
720
  entry.files = files
657
721
  const map = Mapping.toEncodedMap(new Mapping.GenMapping())
658
722
  return {
723
+ imports,
724
+ modules: result.modules,
659
725
  code: output.code,
660
726
  contractIds: Object.keys(result.contracts),
661
727
  css: '',
@@ -897,6 +963,8 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
897
963
  entry.files = files
898
964
 
899
965
  return {
966
+ imports,
967
+ modules: result.modules,
900
968
  code: output.code,
901
969
  contractIds: Object.keys(compiled),
902
970
  css: styles.join('\n'),
@@ -915,6 +983,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
915
983
  /** Compiles every discovered source once so index.html can inline each configuration's script before modules load. */
916
984
  async function initializations(server: ViteDevServer) {
917
985
  const environment = server.environments.client
986
+ reads.delete(environment)
918
987
  const host: Host = {
919
988
  asset: async (file) => file,
920
989
  resolve: (source, importer) =>
@@ -930,7 +999,7 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
930
999
  if (file === undefined) return []
931
1000
 
932
1001
  entry = {
933
- compiler: Graph.create(),
1002
+ compiler: compiler(environment),
934
1003
  environment,
935
1004
  file,
936
1005
  files: new Set([file]),
@@ -1097,6 +1166,9 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
1097
1166
  }
1098
1167
 
1099
1168
  return {
1169
+ buildStart() {
1170
+ reads.delete(this.environment)
1171
+ },
1100
1172
  config: {
1101
1173
  order: 'post',
1102
1174
  handler(config) {
@@ -1241,27 +1313,73 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
1241
1313
  async watchChange(file, change) {
1242
1314
  await updateDiscovery(this.environment, file, change.event)
1243
1315
  },
1244
- async hotUpdate({ file, modules, timestamp, type }) {
1316
+ async hotUpdate({ file, modules, timestamp, type, server }) {
1245
1317
  await updateDiscovery(this.environment, file, type)
1246
1318
 
1247
- const affected = new Set(modules)
1319
+ const state = entries(this.environment)
1320
+ const first = [...state.values()].find(
1321
+ (entry) => entry.files.has(file) || eager(file),
1322
+ )
1323
+ if (!first && !removed.get(this.environment)?.has(file)) return modules
1324
+
1325
+ // Failed edits retain normal invalidation so Vite reports errors on reload.
1326
+ const output =
1327
+ first && type === 'update' && eligible(file)
1328
+ ? await compile(
1329
+ first,
1330
+ {
1331
+ resolve: (source, importer) =>
1332
+ this.environment.pluginContainer.resolveId(source, importer),
1333
+ watch: (file) => {
1334
+ server.watcher.add(file)
1335
+ },
1336
+ asset: async (file) => file,
1337
+ },
1338
+ undefined,
1339
+ true,
1340
+ true,
1341
+ ).catch(() => undefined)
1342
+ : undefined
1343
+ const affected = new Set(
1344
+ modules.filter((module) => {
1345
+ const entry = module.id && state.get(module.id)
1346
+ return (
1347
+ !output ||
1348
+ !entry ||
1349
+ entry.code !== output.modules[sourceId(entry.file)]?.code ||
1350
+ entry.imports !==
1351
+ JSON.stringify(output.imports[sourceId(entry.file)])
1352
+ )
1353
+ }),
1354
+ )
1355
+ const ids = new Set<string>()
1356
+ if (type === 'delete') ids.add(cssId(file))
1248
1357
 
1249
1358
  for (const entry of entries(this.environment).values()) {
1250
1359
  if (!entry.files.has(file) && !eager(file)) continue
1251
1360
 
1252
1361
  // Theme scopes affect CSS even when Vite's JavaScript import was erased.
1253
- for (const id of [entry.file, cssId(entry.file), sharedId]) {
1254
- const module = this.environment.moduleGraph.getModuleById(id)
1255
- if (!module) continue
1256
-
1257
- this.environment.moduleGraph.invalidateModule(
1258
- module,
1259
- new Set(),
1260
- timestamp,
1261
- true,
1262
- )
1263
- affected.add(module)
1264
- }
1362
+ if (
1363
+ !output ||
1364
+ entry.code !== output.modules[sourceId(entry.file)]?.code ||
1365
+ entry.imports !== JSON.stringify(output.imports[sourceId(entry.file)])
1366
+ )
1367
+ ids.add(entry.file)
1368
+ ids.add(cssId(entry.file))
1369
+ ids.add(sharedId)
1370
+ }
1371
+
1372
+ for (const id of ids) {
1373
+ const module = this.environment.moduleGraph.getModuleById(id)
1374
+ if (!module) continue
1375
+
1376
+ this.environment.moduleGraph.invalidateModule(
1377
+ module,
1378
+ new Set(),
1379
+ timestamp,
1380
+ true,
1381
+ )
1382
+ affected.add(module)
1265
1383
  }
1266
1384
 
1267
1385
  return [...affected]
@@ -1278,6 +1396,8 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
1278
1396
  file === undefined
1279
1397
  ? entries(this.environment).values().next().value
1280
1398
  : entries(this.environment).get(file)
1399
+ // A pruned JavaScript module can leave its stylesheet loaded in the browser.
1400
+ if (!entry && file && removed.get(this.environment)?.has(file)) return ''
1281
1401
  if (!entry) throw new Error(`Unknown Zyzz stylesheet: ${file}`)
1282
1402
 
1283
1403
  const output = await compile(
@@ -1333,12 +1453,13 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
1333
1453
 
1334
1454
  if (!entry) {
1335
1455
  entry = {
1336
- compiler: Graph.create(),
1456
+ compiler: compiler(this.environment),
1337
1457
  environment: this.environment,
1338
1458
  file: id,
1339
1459
  files: new Set([id]),
1340
1460
  }
1341
1461
  state.set(id, entry)
1462
+ removed.get(this.environment)?.delete(id)
1342
1463
  }
1343
1464
 
1344
1465
  const output = await compile(
@@ -1360,6 +1481,9 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
1360
1481
  code,
1361
1482
  )
1362
1483
 
1484
+ entry.imports = JSON.stringify(output.imports[sourceId(entry.file)])
1485
+ entry.code = output.code
1486
+
1363
1487
  if (native) return { code: output.code, map: JSON.stringify(output.map) }
1364
1488
 
1365
1489
  // Keep the CSS dependency even when the current graph has no live rules.
@@ -1459,6 +1583,8 @@ export function zyzz(options: zyzz.Options = {}): Plugin {
1459
1583
  }
1460
1584
 
1461
1585
  type Entry = {
1586
+ code?: string
1587
+ imports?: string
1462
1588
  environment: Environment
1463
1589
  compiler: Graph.create.ReturnType
1464
1590
  file: string