one 1.25.16 → 1.26.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.
Files changed (78) hide show
  1. package/dist/cjs/native-transforms.cjs +28 -0
  2. package/dist/cjs/native-transforms.native.js +31 -0
  3. package/dist/cjs/native-transforms.native.js.map +1 -0
  4. package/dist/cjs/router/useViteRoutes.cjs +3 -2
  5. package/dist/cjs/router/useViteRoutes.native.js +3 -2
  6. package/dist/cjs/router/useViteRoutes.native.js.map +1 -1
  7. package/dist/cjs/router/useViteRoutes.test.cjs +101 -1
  8. package/dist/cjs/router/useViteRoutes.test.native.js +109 -1
  9. package/dist/cjs/router/useViteRoutes.test.native.js.map +1 -1
  10. package/dist/cjs/vercel/build/generate/createApiServerlessFunction.cjs +45 -44
  11. package/dist/cjs/vercel/build/generate/createApiServerlessFunction.native.js +64 -39
  12. package/dist/cjs/vercel/build/generate/createApiServerlessFunction.native.js.map +1 -1
  13. package/dist/cjs/vite/one.cjs +10 -2
  14. package/dist/cjs/vite/one.native.js +13 -4
  15. package/dist/cjs/vite/one.native.js.map +1 -1
  16. package/dist/cjs/vite/plugins/clientTreeShakePlugin.cjs +597 -92
  17. package/dist/cjs/vite/plugins/clientTreeShakePlugin.native.js +1358 -113
  18. package/dist/cjs/vite/plugins/clientTreeShakePlugin.native.js.map +1 -1
  19. package/dist/cjs/vite/plugins/clientTreeShakePlugin.test.cjs +185 -0
  20. package/dist/cjs/vite/plugins/clientTreeShakePlugin.test.native.js +185 -0
  21. package/dist/cjs/vite/plugins/clientTreeShakePlugin.test.native.js.map +1 -1
  22. package/dist/cjs/vite/plugins/useDomPlugin.cjs +14 -37
  23. package/dist/cjs/vite/plugins/useDomPlugin.native.js +14 -36
  24. package/dist/cjs/vite/plugins/useDomPlugin.native.js.map +1 -1
  25. package/dist/esm/native-transforms.mjs +3 -0
  26. package/dist/esm/native-transforms.mjs.map +1 -0
  27. package/dist/esm/native-transforms.native.js +3 -0
  28. package/dist/esm/native-transforms.native.js.map +1 -0
  29. package/dist/esm/router/useViteRoutes.mjs +3 -2
  30. package/dist/esm/router/useViteRoutes.mjs.map +1 -1
  31. package/dist/esm/router/useViteRoutes.native.js +3 -2
  32. package/dist/esm/router/useViteRoutes.native.js.map +1 -1
  33. package/dist/esm/router/useViteRoutes.test.mjs +77 -1
  34. package/dist/esm/router/useViteRoutes.test.mjs.map +1 -1
  35. package/dist/esm/router/useViteRoutes.test.native.js +85 -1
  36. package/dist/esm/router/useViteRoutes.test.native.js.map +1 -1
  37. package/dist/esm/vercel/build/generate/createApiServerlessFunction.mjs +45 -44
  38. package/dist/esm/vercel/build/generate/createApiServerlessFunction.mjs.map +1 -1
  39. package/dist/esm/vercel/build/generate/createApiServerlessFunction.native.js +64 -39
  40. package/dist/esm/vercel/build/generate/createApiServerlessFunction.native.js.map +1 -1
  41. package/dist/esm/vite/one.mjs +10 -2
  42. package/dist/esm/vite/one.mjs.map +1 -1
  43. package/dist/esm/vite/one.native.js +13 -4
  44. package/dist/esm/vite/one.native.js.map +1 -1
  45. package/dist/esm/vite/plugins/clientTreeShakePlugin.mjs +597 -92
  46. package/dist/esm/vite/plugins/clientTreeShakePlugin.mjs.map +1 -1
  47. package/dist/esm/vite/plugins/clientTreeShakePlugin.native.js +1358 -113
  48. package/dist/esm/vite/plugins/clientTreeShakePlugin.native.js.map +1 -1
  49. package/dist/esm/vite/plugins/clientTreeShakePlugin.test.mjs +185 -0
  50. package/dist/esm/vite/plugins/clientTreeShakePlugin.test.mjs.map +1 -1
  51. package/dist/esm/vite/plugins/clientTreeShakePlugin.test.native.js +185 -0
  52. package/dist/esm/vite/plugins/clientTreeShakePlugin.test.native.js.map +1 -1
  53. package/dist/esm/vite/plugins/useDomPlugin.mjs +13 -25
  54. package/dist/esm/vite/plugins/useDomPlugin.mjs.map +1 -1
  55. package/dist/esm/vite/plugins/useDomPlugin.native.js +14 -25
  56. package/dist/esm/vite/plugins/useDomPlugin.native.js.map +1 -1
  57. package/package.json +15 -10
  58. package/src/createApp.tsx +0 -1
  59. package/src/headless.tsx +0 -1
  60. package/src/native-transforms.ts +11 -0
  61. package/src/router/useViteRoutes.test.ts +91 -0
  62. package/src/router/useViteRoutes.tsx +7 -4
  63. package/src/vercel/build/generate/createApiServerlessFunction.ts +65 -112
  64. package/src/vite/one.ts +22 -2
  65. package/src/vite/plugins/clientTreeShakePlugin.test.ts +201 -0
  66. package/src/vite/plugins/clientTreeShakePlugin.ts +732 -152
  67. package/src/vite/plugins/useDomPlugin.ts +20 -32
  68. package/src/vite/types.ts +60 -5
  69. package/types/native-transforms.d.ts +11 -0
  70. package/types/native-transforms.d.ts.map +1 -0
  71. package/types/router/useViteRoutes.d.ts.map +1 -1
  72. package/types/vercel/build/generate/createApiServerlessFunction.d.ts.map +1 -1
  73. package/types/vite/one.d.ts.map +1 -1
  74. package/types/vite/plugins/clientTreeShakePlugin.d.ts +1 -9
  75. package/types/vite/plugins/clientTreeShakePlugin.d.ts.map +1 -1
  76. package/types/vite/plugins/useDomPlugin.d.ts.map +1 -1
  77. package/types/vite/types.d.ts +57 -5
  78. package/types/vite/types.d.ts.map +1 -1
@@ -335,5 +335,206 @@ export default function Page() {
335
335
  // Runtime import should be removed
336
336
  expect(result!.code).not.toContain('discord-client')
337
337
  })
338
+
339
+ it('should preserve side-effect imports during tree shaking', async () => {
340
+ const code = `
341
+ import './style.css'
342
+ import { serverOnlyModule } from 'server-only-pkg'
343
+ import { Text } from 'react-native'
344
+
345
+ export function loader() {
346
+ return serverOnlyModule()
347
+ }
348
+
349
+ export default function Page() {
350
+ return <Text>Hello</Text>
351
+ }
352
+ `
353
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
354
+ expect(result).toBeDefined()
355
+ expect(result!.code).toContain("import './style.css'")
356
+ expect(result!.code).not.toContain('server-only-pkg')
357
+ })
358
+
359
+ it('should remove transitive local bindings exclusively used by loader', async () => {
360
+ const code = `
361
+ import { db } from 'server-only-db'
362
+ import { Text } from 'react-native'
363
+
364
+ const secretKey = 'my-secret'
365
+
366
+ function querySecret() {
367
+ return db.query(secretKey)
368
+ }
369
+
370
+ export async function loader() {
371
+ return querySecret()
372
+ }
373
+
374
+ export default function Page() {
375
+ return <Text>Hello</Text>
376
+ }
377
+ `
378
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
379
+ expect(result).toBeDefined()
380
+ expect(result!.code).not.toContain('server-only-db')
381
+ expect(result!.code).not.toContain('secretKey')
382
+ expect(result!.code).not.toContain('querySecret')
383
+ expect(result!.code).toContain('export default function Page')
384
+ })
385
+
386
+ it('should preserve shared local bindings used by both loader and client', async () => {
387
+ const code = `
388
+ import { serverOnlyModule } from 'server-only-pkg'
389
+ import { Text } from 'react-native'
390
+
391
+ const sharedConfig = { siteName: 'One' }
392
+
393
+ function getTitle() {
394
+ return sharedConfig.siteName
395
+ }
396
+
397
+ export function loader() {
398
+ serverOnlyModule()
399
+ return getTitle()
400
+ }
401
+
402
+ export default function Page() {
403
+ return <Text>{getTitle()}</Text>
404
+ }
405
+ `
406
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
407
+ expect(result).toBeDefined()
408
+ expect(result!.code).not.toContain('server-only-pkg')
409
+ expect(result!.code).toContain('sharedConfig')
410
+ expect(result!.code).toContain('getTitle')
411
+ })
412
+
413
+ it('should throw build error on syntax error in production', async () => {
414
+ const origEnv = process.env.NODE_ENV
415
+ try {
416
+ process.env.NODE_ENV = 'production'
417
+ const code = `
418
+ import { serverOnly } from 'server-only-pkg'
419
+ export function loader() {
420
+ bad syntax {
421
+ }
422
+ `
423
+ await expect(transformTreeShakeClient(code, '/app/index.tsx')).rejects.toThrow(
424
+ /Failed to parse/
425
+ )
426
+ } finally {
427
+ process.env.NODE_ENV = origEnv
428
+ }
429
+ })
430
+
431
+ it('should log warning and return undefined on syntax error in development', async () => {
432
+ const origEnv = process.env.NODE_ENV
433
+ try {
434
+ process.env.NODE_ENV = 'development'
435
+ const code = `
436
+ import { serverOnly } from 'server-only-pkg'
437
+ export function loader() {
438
+ bad syntax {
439
+ }
440
+ `
441
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
442
+ expect(result).toBeUndefined()
443
+ } finally {
444
+ process.env.NODE_ENV = origEnv
445
+ }
446
+ })
447
+
448
+ it('should generate a valid sourcemap', async () => {
449
+ const code = `
450
+ import { serverOnlyModule } from 'server-only-pkg'
451
+ import { Text } from 'react-native'
452
+
453
+ export function loader() {
454
+ return serverOnlyModule()
455
+ }
456
+
457
+ export default function Page() {
458
+ return <Text>Hello</Text>
459
+ }
460
+ `
461
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
462
+ expect(result).toBeDefined()
463
+ expect(result!.map).toBeDefined()
464
+ expect(result!.map.mappings).toBeDefined()
465
+ })
466
+
467
+ it('preserves shared import referenced in destructuring default parameter', async () => {
468
+ const code = `import {shared} from "./shared"; export function loader(){return shared}; export default function Page({x = shared}) {return x}`
469
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
470
+ expect(result).toBeDefined()
471
+ expect(result!.code).toContain('import {shared} from "./shared"')
472
+ expect(result!.code).toContain('Page({x = shared})')
473
+ expect(result!.code).toContain('export function loader()')
474
+ })
475
+
476
+ it('preserves shared import referenced in top-level executable statement', async () => {
477
+ const code = `import {shared} from "./shared"; export function loader(){return shared}; if (globalThis.ready) shared();`
478
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
479
+ expect(result).toBeDefined()
480
+ expect(result!.code).toContain('import {shared} from "./shared"')
481
+ expect(result!.code).toContain('if (globalThis.ready) shared();')
482
+ expect(result!.code).toContain('export function loader()')
483
+ })
484
+
485
+ it('preserves shared import referenced in top-level retained initializer', async () => {
486
+ const code = `import {shared} from "./shared"; const retained = shared(); export function loader(){return shared}; export default function Page(){return null}`
487
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
488
+ expect(result).toBeDefined()
489
+ expect(result!.code).toContain('import {shared} from "./shared"')
490
+ expect(result!.code).toContain('const retained = shared();')
491
+ expect(result!.code).toContain('export function loader()')
492
+ })
493
+
494
+ it('removes top-level declaration and import used exclusively by loader', async () => {
495
+ const code = `import {secret} from "./secret"; const localSecret = secret(); export function loader(){return localSecret}; export default function Page(){return null}`
496
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
497
+ expect(result).toBeDefined()
498
+ expect(result!.code).not.toContain('./secret')
499
+ expect(result!.code).not.toContain('localSecret')
500
+ expect(result!.code).toContain('export function loader()')
501
+ })
502
+
503
+ it('preserves shared import referenced in top-level destructuring default binding', async () => {
504
+ const code = `import {shared} from "./shared"; const {x = shared} = {}; export function loader(){return [x,shared]}; export default function Page(){return x}`
505
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
506
+ expect(result).toBeDefined()
507
+ expect(result!.code).toContain('import {shared} from "./shared"')
508
+ expect(result!.code).toContain('const {x = shared} = {}')
509
+ expect(result!.code).toContain('return x')
510
+ })
511
+
512
+ it('removes server-only import referenced in top-level destructuring default binding when used only by loader', async () => {
513
+ const code = `import {secret} from "./server"; const {x = secret} = {}; export function loader(){return x}; export default function Page(){return null}`
514
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
515
+ expect(result).toBeDefined()
516
+ expect(result!.code).not.toContain('./server')
517
+ expect(result!.code).not.toContain('secret')
518
+ expect(result!.code).not.toContain('{x = secret}')
519
+ expect(result!.code).toContain('Page(){return null}')
520
+ })
521
+
522
+ it('removes server-only enum and class declarations used only by loader', async () => {
523
+ const code = `import {server} from "./server"; enum E { X = server() }; export function loader() {return E.X}; export default function Page(){return null}`
524
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
525
+ expect(result).toBeDefined()
526
+ expect(result!.code).not.toContain('./server')
527
+ expect(result!.code).not.toContain('enum E')
528
+ expect(result!.code).toContain('Page(){return null}')
529
+ })
530
+
531
+ it('preserves shared enum used by both loader and client Page', async () => {
532
+ const code = `import {shared} from "./shared"; enum E { X = shared() }; export function loader() {return E.X}; export default function Page(){return E.X}`
533
+ const result = await transformTreeShakeClient(code, '/app/index.tsx')
534
+ expect(result).toBeDefined()
535
+ expect(result!.code).toContain('import {shared} from "./shared"')
536
+ expect(result!.code).toContain('enum E')
537
+ expect(result!.code).toContain('Page(){return E.X}')
538
+ })
338
539
  })
339
540
  })