@despia/local 1.0.0 → 1.0.2
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/README.md +108 -35
- package/generate-offline-manifest.js +66 -6
- package/package.json +1 -1
- package/src/astro.js +4 -4
- package/src/core.js +9 -6
- package/src/esbuild.js +4 -4
- package/src/index.js +10 -10
- package/src/next.js +43 -18
- package/src/nuxt.js +6 -6
- package/src/parcel.js +3 -3
- package/src/remix.js +4 -4
- package/src/rollup.js +2 -2
- package/src/sveltekit.js +4 -4
- package/src/turbopack.js +2 -2
- package/src/vite.js +2 -2
- package/src/webpack.js +19 -4
package/README.md
CHANGED
|
@@ -353,12 +353,12 @@ npx despia-local [outputDir] [entryHtml]
|
|
|
353
353
|
```javascript
|
|
354
354
|
// vite.config.js
|
|
355
355
|
import { defineConfig } from 'vite';
|
|
356
|
-
import {
|
|
356
|
+
import { despiaLocalPlugin } from '@despia/local/vite';
|
|
357
357
|
|
|
358
358
|
export default defineConfig({
|
|
359
359
|
plugins: [
|
|
360
360
|
// ... your other plugins
|
|
361
|
-
|
|
361
|
+
despiaLocalPlugin({
|
|
362
362
|
outDir: 'dist', // optional, default: 'dist'
|
|
363
363
|
entryHtml: 'index.html' // optional, default: 'index.html'
|
|
364
364
|
})
|
|
@@ -378,13 +378,13 @@ export default defineConfig({
|
|
|
378
378
|
|
|
379
379
|
```javascript
|
|
380
380
|
// webpack.config.js
|
|
381
|
-
const
|
|
381
|
+
const DespiaLocalPlugin = require('@despia/local/webpack');
|
|
382
382
|
|
|
383
383
|
module.exports = {
|
|
384
384
|
// ... your config
|
|
385
385
|
plugins: [
|
|
386
386
|
// ... your other plugins
|
|
387
|
-
new
|
|
387
|
+
new DespiaLocalPlugin({
|
|
388
388
|
outDir: 'dist', // optional, default: 'dist'
|
|
389
389
|
entryHtml: 'index.html' // optional, default: 'index.html'
|
|
390
390
|
})
|
|
@@ -402,13 +402,13 @@ module.exports = {
|
|
|
402
402
|
|
|
403
403
|
```javascript
|
|
404
404
|
// rollup.config.js
|
|
405
|
-
import {
|
|
405
|
+
import { despiaLocal } from '@despia/local/rollup';
|
|
406
406
|
|
|
407
407
|
export default {
|
|
408
408
|
// ... your config
|
|
409
409
|
plugins: [
|
|
410
410
|
// ... your other plugins
|
|
411
|
-
|
|
411
|
+
despiaLocal({
|
|
412
412
|
outDir: 'dist',
|
|
413
413
|
entryHtml: 'index.html'
|
|
414
414
|
})
|
|
@@ -418,25 +418,28 @@ export default {
|
|
|
418
418
|
|
|
419
419
|
### Next.js
|
|
420
420
|
|
|
421
|
+
**For static export (recommended for static sites):**
|
|
422
|
+
|
|
421
423
|
```javascript
|
|
422
424
|
// next.config.js
|
|
423
|
-
const
|
|
425
|
+
const withDespiaLocal = require('@despia/local/next');
|
|
424
426
|
|
|
425
|
-
module.exports =
|
|
427
|
+
module.exports = withDespiaLocal({
|
|
426
428
|
entryHtml: 'index.html',
|
|
427
|
-
outDir: '
|
|
429
|
+
outDir: 'out' // Next.js static export directory
|
|
428
430
|
})({
|
|
431
|
+
output: 'export',
|
|
429
432
|
// your Next.js config
|
|
430
433
|
});
|
|
431
434
|
```
|
|
432
435
|
|
|
433
|
-
**For static export:**
|
|
436
|
+
**For static export (alternative):**
|
|
434
437
|
|
|
435
438
|
```javascript
|
|
436
439
|
// next.config.js
|
|
437
|
-
const
|
|
440
|
+
const withDespiaLocal = require('@despia/local/next');
|
|
438
441
|
|
|
439
|
-
module.exports =
|
|
442
|
+
module.exports = withDespiaLocal({
|
|
440
443
|
outDir: 'out', // Next.js static export directory
|
|
441
444
|
entryHtml: 'index.html'
|
|
442
445
|
})({
|
|
@@ -445,29 +448,75 @@ module.exports = withDespiaOffline({
|
|
|
445
448
|
});
|
|
446
449
|
```
|
|
447
450
|
|
|
448
|
-
**Alternative: Webpack Plugin Approach
|
|
451
|
+
**Alternative: Webpack Plugin Approach (works best for static export):**
|
|
449
452
|
|
|
450
453
|
```javascript
|
|
451
454
|
// next.config.js
|
|
452
|
-
const
|
|
455
|
+
const DespiaLocalPlugin = require('@despia/local/webpack');
|
|
453
456
|
|
|
454
457
|
module.exports = {
|
|
458
|
+
output: 'export', // For static export
|
|
455
459
|
webpack: (config) => {
|
|
456
460
|
config.plugins.push(
|
|
457
|
-
new
|
|
461
|
+
new DespiaLocalPlugin({ outDir: 'out' })
|
|
458
462
|
);
|
|
459
463
|
return config;
|
|
460
464
|
}
|
|
461
465
|
};
|
|
462
466
|
```
|
|
463
467
|
|
|
468
|
+
**Note**: The webpack plugin approach works best for static export. For SSR apps, use the post-build script approach described below.
|
|
469
|
+
|
|
470
|
+
**For SSR (Server-Side Rendering) apps:**
|
|
471
|
+
|
|
472
|
+
SSR Next.js apps require special handling because:
|
|
473
|
+
- Client assets are in `.next/static/` directory (not `.next/`)
|
|
474
|
+
- No static HTML files exist (pages are server-rendered)
|
|
475
|
+
- Manifest should only include client-side assets (JS, CSS, images)
|
|
476
|
+
- Server-side code in `.next/server/` should NOT be included
|
|
477
|
+
|
|
478
|
+
**Recommended approach for SSR (most reliable):**
|
|
479
|
+
|
|
480
|
+
Use a post-build script in your `package.json`:
|
|
481
|
+
|
|
482
|
+
```json
|
|
483
|
+
{
|
|
484
|
+
"scripts": {
|
|
485
|
+
"build": "next build",
|
|
486
|
+
"postbuild": "despia-local .next/static"
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
This approach:
|
|
492
|
+
- Runs after Next.js build completes
|
|
493
|
+
- Targets `.next/static/` where all client assets are stored
|
|
494
|
+
- Works reliably for both SSR and static export
|
|
495
|
+
- No `entryHtml` needed (SSR apps don't have static HTML files)
|
|
496
|
+
|
|
497
|
+
**Alternative: Using the plugin (may have timing issues):**
|
|
498
|
+
|
|
499
|
+
```javascript
|
|
500
|
+
// next.config.js
|
|
501
|
+
const withDespiaLocal = require('@despia/local/next');
|
|
502
|
+
|
|
503
|
+
module.exports = withDespiaLocal({
|
|
504
|
+
// entryHtml is optional for SSR (not used)
|
|
505
|
+
outDir: '.next/static' // Target client assets directory
|
|
506
|
+
})({
|
|
507
|
+
// your Next.js config (SSR mode - no output: 'export')
|
|
508
|
+
});
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
**Note**: The plugin approach may not work reliably for SSR because Next.js doesn't provide a reliable build completion hook. The post-build script approach is recommended for SSR apps.
|
|
512
|
+
|
|
464
513
|
### Nuxt
|
|
465
514
|
|
|
466
515
|
```javascript
|
|
467
516
|
// nuxt.config.js
|
|
468
517
|
export default {
|
|
469
518
|
modules: ['@despia/local/nuxt'],
|
|
470
|
-
|
|
519
|
+
despiaLocal: {
|
|
471
520
|
entryHtml: 'index.html'
|
|
472
521
|
}
|
|
473
522
|
}
|
|
@@ -476,9 +525,9 @@ export default {
|
|
|
476
525
|
**Or as a local module:**
|
|
477
526
|
|
|
478
527
|
```javascript
|
|
479
|
-
// modules/despia-
|
|
480
|
-
import
|
|
481
|
-
export default
|
|
528
|
+
// modules/despia-local.js
|
|
529
|
+
import DespiaLocalModule from '@despia/local/nuxt';
|
|
530
|
+
export default DespiaLocalModule;
|
|
482
531
|
```
|
|
483
532
|
|
|
484
533
|
### SvelteKit
|
|
@@ -486,12 +535,12 @@ export default DespiaOfflineModule;
|
|
|
486
535
|
```javascript
|
|
487
536
|
// vite.config.js
|
|
488
537
|
import { sveltekit } from '@sveltejs/kit/vite';
|
|
489
|
-
import {
|
|
538
|
+
import { despiaLocalSvelteKit } from '@despia/local/sveltekit';
|
|
490
539
|
|
|
491
540
|
export default {
|
|
492
541
|
plugins: [
|
|
493
542
|
sveltekit(),
|
|
494
|
-
|
|
543
|
+
despiaLocalSvelteKit({
|
|
495
544
|
entryHtml: 'index.html'
|
|
496
545
|
})
|
|
497
546
|
]
|
|
@@ -503,11 +552,11 @@ export default {
|
|
|
503
552
|
```javascript
|
|
504
553
|
// astro.config.mjs
|
|
505
554
|
import { defineConfig } from 'astro/config';
|
|
506
|
-
import
|
|
555
|
+
import despiaLocal from '@despia/local/astro';
|
|
507
556
|
|
|
508
557
|
export default defineConfig({
|
|
509
558
|
integrations: [
|
|
510
|
-
|
|
559
|
+
despiaLocal({
|
|
511
560
|
entryHtml: 'index.html',
|
|
512
561
|
outDir: 'dist'
|
|
513
562
|
})
|
|
@@ -520,12 +569,12 @@ export default defineConfig({
|
|
|
520
569
|
```javascript
|
|
521
570
|
// vite.config.js (Remix uses Vite)
|
|
522
571
|
import { remix } from '@remix-run/dev';
|
|
523
|
-
import {
|
|
572
|
+
import { despiaLocalRemix } from '@despia/local/remix';
|
|
524
573
|
|
|
525
574
|
export default {
|
|
526
575
|
plugins: [
|
|
527
576
|
remix(),
|
|
528
|
-
|
|
577
|
+
despiaLocalRemix({
|
|
529
578
|
entryHtml: 'index.html',
|
|
530
579
|
outDir: 'build/client'
|
|
531
580
|
})
|
|
@@ -537,13 +586,13 @@ export default {
|
|
|
537
586
|
|
|
538
587
|
```javascript
|
|
539
588
|
import { build } from 'esbuild';
|
|
540
|
-
import {
|
|
589
|
+
import { despiaLocalEsbuild } from '@despia/local/esbuild';
|
|
541
590
|
|
|
542
591
|
await build({
|
|
543
592
|
entryPoints: ['src/index.js'],
|
|
544
593
|
outdir: 'dist',
|
|
545
594
|
plugins: [
|
|
546
|
-
|
|
595
|
+
despiaLocalEsbuild({
|
|
547
596
|
outDir: 'dist',
|
|
548
597
|
entryHtml: 'index.html'
|
|
549
598
|
})
|
|
@@ -618,12 +667,12 @@ The generated `despia/local.json` file contains a sorted JSON array of root-rela
|
|
|
618
667
|
// vite.config.js
|
|
619
668
|
import { defineConfig } from 'vite';
|
|
620
669
|
import react from '@vitejs/plugin-react';
|
|
621
|
-
import {
|
|
670
|
+
import { despiaLocalPlugin } from '@despia/local/vite';
|
|
622
671
|
|
|
623
672
|
export default defineConfig({
|
|
624
673
|
plugins: [
|
|
625
674
|
react(),
|
|
626
|
-
|
|
675
|
+
despiaLocalPlugin()
|
|
627
676
|
]
|
|
628
677
|
});
|
|
629
678
|
```
|
|
@@ -634,12 +683,12 @@ export default defineConfig({
|
|
|
634
683
|
// vite.config.js
|
|
635
684
|
import { defineConfig } from 'vite';
|
|
636
685
|
import vue from '@vitejs/plugin-vue';
|
|
637
|
-
import {
|
|
686
|
+
import { despiaLocalPlugin } from '@despia/local/vite';
|
|
638
687
|
|
|
639
688
|
export default defineConfig({
|
|
640
689
|
plugins: [
|
|
641
690
|
vue(),
|
|
642
|
-
|
|
691
|
+
despiaLocalPlugin()
|
|
643
692
|
]
|
|
644
693
|
});
|
|
645
694
|
```
|
|
@@ -668,11 +717,11 @@ export default defineConfig({
|
|
|
668
717
|
|
|
669
718
|
```javascript
|
|
670
719
|
// webpack.config.js
|
|
671
|
-
const
|
|
720
|
+
const DespiaLocalPlugin = require('@despia/local/webpack');
|
|
672
721
|
|
|
673
722
|
module.exports = {
|
|
674
723
|
plugins: [
|
|
675
|
-
new
|
|
724
|
+
new DespiaLocalPlugin({ outDir: 'dist' })
|
|
676
725
|
]
|
|
677
726
|
};
|
|
678
727
|
```
|
|
@@ -683,12 +732,12 @@ module.exports = {
|
|
|
683
732
|
// vite.config.js
|
|
684
733
|
import { defineConfig } from 'vite';
|
|
685
734
|
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
|
686
|
-
import {
|
|
735
|
+
import { despiaLocalPlugin } from '@despia/local/vite';
|
|
687
736
|
|
|
688
737
|
export default defineConfig({
|
|
689
738
|
plugins: [
|
|
690
739
|
svelte(),
|
|
691
|
-
|
|
740
|
+
despiaLocalPlugin()
|
|
692
741
|
]
|
|
693
742
|
});
|
|
694
743
|
```
|
|
@@ -733,6 +782,30 @@ The generated manifest is then used by Despia during app hydration and updates t
|
|
|
733
782
|
- Paths starting with `/` are preserved as-is
|
|
734
783
|
- Windows backslashes are converted to forward slashes
|
|
735
784
|
|
|
785
|
+
### Next.js SSR Issues
|
|
786
|
+
|
|
787
|
+
**Manifest not generated for SSR app:**
|
|
788
|
+
|
|
789
|
+
1. Ensure you're targeting `.next/static/` directory (not `.next/`)
|
|
790
|
+
2. Use the post-build script approach: `"postbuild": "despia-local .next/static"`
|
|
791
|
+
3. Verify build completed successfully: `next build` should finish without errors
|
|
792
|
+
4. Check that `.next/static/` directory exists after build
|
|
793
|
+
5. The plugin approach may not work reliably for SSR - prefer post-build script
|
|
794
|
+
|
|
795
|
+
**Missing assets in SSR manifest:**
|
|
796
|
+
|
|
797
|
+
- SSR apps only need client assets (JS, CSS, images)
|
|
798
|
+
- Server-side code in `.next/server/` is NOT included (correct behavior)
|
|
799
|
+
- Only assets in `.next/static/` should be in the manifest
|
|
800
|
+
- Verify you're scanning `.next/static/` not `.next/` or `.next/server/`
|
|
801
|
+
|
|
802
|
+
**Wrong directory for SSR:**
|
|
803
|
+
|
|
804
|
+
If you see errors about missing directories:
|
|
805
|
+
- For SSR: Use `.next/static/` (client assets only)
|
|
806
|
+
- For static export: Use `out/` (full static site)
|
|
807
|
+
- Never use `.next/server/` (server code, not needed for manifest)
|
|
808
|
+
|
|
736
809
|
## Contributing
|
|
737
810
|
|
|
738
811
|
Contributions welcome! Please open an issue or submit a pull request.
|
|
@@ -14,21 +14,81 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { generateManifest } from './src/core.js';
|
|
17
|
-
import { resolve } from 'path';
|
|
17
|
+
import { resolve, join } from 'path';
|
|
18
|
+
import { existsSync } from 'fs';
|
|
18
19
|
|
|
19
20
|
// Get command line arguments
|
|
20
21
|
const outputDir = process.argv[2] || 'dist';
|
|
21
22
|
const entryHtml = process.argv[3] || 'index.html';
|
|
22
23
|
|
|
24
|
+
// Detect Next.js SSR context
|
|
25
|
+
const isNextJsDir = outputDir.includes('.next');
|
|
26
|
+
const isNextJsStatic = outputDir.includes('.next/static') || outputDir === '.next/static';
|
|
27
|
+
const isNextJsRoot = outputDir === '.next';
|
|
28
|
+
const isNextJsServer = outputDir.includes('.next/server');
|
|
29
|
+
|
|
30
|
+
// Determine if we should skip entryHtml (for SSR apps)
|
|
31
|
+
const skipEntryHtml = isNextJsStatic || isNextJsServer;
|
|
32
|
+
|
|
33
|
+
// Provide helpful messages for Next.js
|
|
34
|
+
if (isNextJsDir && !isNextJsStatic && !isNextJsServer) {
|
|
35
|
+
if (isNextJsRoot) {
|
|
36
|
+
console.warn('⚠ Warning: Scanning .next/ directory directly.');
|
|
37
|
+
console.warn('💡 For SSR apps, use: despia-local .next/static');
|
|
38
|
+
console.warn('💡 For static export, use: despia-local out');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (isNextJsServer) {
|
|
43
|
+
console.error('❌ Error: .next/server/ contains server-side code, not client assets.');
|
|
44
|
+
console.error('💡 For SSR apps, use: despia-local .next/static');
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
23
48
|
try {
|
|
24
|
-
|
|
25
|
-
|
|
49
|
+
const resolvedPath = resolve(process.cwd(), outputDir);
|
|
50
|
+
console.log(`Scanning ${resolvedPath} for assets...`);
|
|
51
|
+
|
|
52
|
+
// Check if directory exists, and provide helpful suggestions for Next.js
|
|
53
|
+
if (!existsSync(resolvedPath)) {
|
|
54
|
+
if (isNextJsRoot) {
|
|
55
|
+
console.error(`❌ Directory "${resolvedPath}" does not exist.`);
|
|
56
|
+
console.error('💡 For SSR apps, try: despia-local .next/static');
|
|
57
|
+
console.error('💡 For static export, try: despia-local out');
|
|
58
|
+
}
|
|
59
|
+
throw new Error(`Output directory "${resolvedPath}" does not exist.`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Check for Next.js static directory and suggest if scanning wrong location
|
|
63
|
+
if (isNextJsRoot && existsSync(join(resolvedPath, 'static'))) {
|
|
64
|
+
console.warn('⚠ Found .next/static/ subdirectory.');
|
|
65
|
+
console.warn('💡 For SSR apps, consider scanning .next/static directly for better results.');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const paths = generateManifest({
|
|
69
|
+
outputDir,
|
|
70
|
+
entryHtml,
|
|
71
|
+
skipEntryHtml
|
|
72
|
+
});
|
|
26
73
|
|
|
27
74
|
console.log(`✓ Generated despia/local.json`);
|
|
28
75
|
console.log(`✓ Included ${paths.length} assets`);
|
|
29
|
-
|
|
76
|
+
if (!skipEntryHtml) {
|
|
77
|
+
console.log(`✓ Entry HTML: /${entryHtml}`);
|
|
78
|
+
} else {
|
|
79
|
+
console.log(`✓ Skipped entry HTML (SSR mode)`);
|
|
80
|
+
}
|
|
30
81
|
} catch (error) {
|
|
31
|
-
console.error(
|
|
32
|
-
console.error('Please run this script after your build completes.');
|
|
82
|
+
console.error(`❌ Error: ${error.message}`);
|
|
83
|
+
console.error('💡 Please run this script after your build completes.');
|
|
84
|
+
|
|
85
|
+
// Additional help for Next.js
|
|
86
|
+
if (isNextJsDir) {
|
|
87
|
+
console.error('');
|
|
88
|
+
console.error('Next.js tips:');
|
|
89
|
+
console.error(' - SSR apps: Use "despia-local .next/static"');
|
|
90
|
+
console.error(' - Static export: Use "despia-local out"');
|
|
91
|
+
}
|
|
92
|
+
|
|
33
93
|
process.exit(1);
|
|
34
94
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@despia/local",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Universal build plugin to generate despia/local.json manifest for offline caching in Despia web-native apps. Supports Vite, Webpack, Rollup, Next.js, Nuxt, SvelteKit, Astro, Remix, esbuild, Parcel, and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/core.js",
|
package/src/astro.js
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Usage in astro.config.mjs:
|
|
5
5
|
* import { defineConfig } from 'astro/config';
|
|
6
|
-
* import
|
|
6
|
+
* import despiaLocal from '@despia/local/astro';
|
|
7
7
|
*
|
|
8
8
|
* export default defineConfig({
|
|
9
9
|
* integrations: [
|
|
10
|
-
*
|
|
10
|
+
* despiaLocal({ entryHtml: 'index.html' })
|
|
11
11
|
* ]
|
|
12
12
|
* });
|
|
13
13
|
*/
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
import { generateManifest } from './core.js';
|
|
16
16
|
import { fileURLToPath } from 'url';
|
|
17
17
|
|
|
18
|
-
export default function
|
|
18
|
+
export default function despiaLocalIntegration(options = {}) {
|
|
19
19
|
const { entryHtml = 'index.html', outDir = 'dist' } = options;
|
|
20
20
|
|
|
21
21
|
return {
|
|
22
|
-
name: 'despia-
|
|
22
|
+
name: 'despia-local',
|
|
23
23
|
hooks: {
|
|
24
24
|
'astro:build:done': async ({ dir }) => {
|
|
25
25
|
// Astro provides dir as a URL object, convert to path
|
package/src/core.js
CHANGED
|
@@ -51,9 +51,10 @@ export function collectFiles(dir, baseDir = dir) {
|
|
|
51
51
|
* @param {string} options.outputDir - Output directory path
|
|
52
52
|
* @param {string} options.entryHtml - Entry HTML filename (default: 'index.html')
|
|
53
53
|
* @param {string[]} options.additionalPaths - Additional paths to include
|
|
54
|
+
* @param {boolean} options.skipEntryHtml - Skip adding entry HTML to manifest (for SSR apps)
|
|
54
55
|
* @returns {string[]} Array of all asset paths
|
|
55
56
|
*/
|
|
56
|
-
export function generateManifest({ outputDir, entryHtml = 'index.html', additionalPaths = [] }) {
|
|
57
|
+
export function generateManifest({ outputDir, entryHtml = 'index.html', additionalPaths = [], skipEntryHtml = false }) {
|
|
57
58
|
const outputPath = resolve(process.cwd(), outputDir);
|
|
58
59
|
const manifestPath = join(outputPath, 'despia', 'local.json');
|
|
59
60
|
|
|
@@ -71,11 +72,13 @@ export function generateManifest({ outputDir, entryHtml = 'index.html', addition
|
|
|
71
72
|
assetPaths.add(normalizedPath);
|
|
72
73
|
});
|
|
73
74
|
|
|
74
|
-
// Ensure entry HTML is included
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
// Ensure entry HTML is included (unless skipped for SSR apps)
|
|
76
|
+
if (!skipEntryHtml) {
|
|
77
|
+
const entryPath = entryHtml.startsWith('/')
|
|
78
|
+
? entryHtml
|
|
79
|
+
: '/' + entryHtml;
|
|
80
|
+
assetPaths.add(entryPath);
|
|
81
|
+
}
|
|
79
82
|
|
|
80
83
|
// Convert to sorted array
|
|
81
84
|
const sortedPaths = Array.from(assetPaths).sort();
|
package/src/esbuild.js
CHANGED
|
@@ -3,21 +3,21 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Usage:
|
|
5
5
|
* import { build } from 'esbuild';
|
|
6
|
-
* import {
|
|
6
|
+
* import { despiaLocalEsbuild } from '@despia/local/esbuild';
|
|
7
7
|
*
|
|
8
8
|
* await build({
|
|
9
|
-
* plugins: [
|
|
9
|
+
* plugins: [despiaLocalEsbuild({ outDir: 'dist' })]
|
|
10
10
|
* });
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { generateManifest } from './core.js';
|
|
14
14
|
import { relative } from 'path';
|
|
15
15
|
|
|
16
|
-
export function
|
|
16
|
+
export function despiaLocalEsbuild(options = {}) {
|
|
17
17
|
const { outDir = 'dist', entryHtml = 'index.html' } = options;
|
|
18
18
|
|
|
19
19
|
return {
|
|
20
|
-
name: 'despia-
|
|
20
|
+
name: 'despia-local',
|
|
21
21
|
setup(build) {
|
|
22
22
|
build.onEnd(async (result) => {
|
|
23
23
|
if (result.errors.length > 0) {
|
package/src/index.js
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
export { generateManifest, collectFiles } from './core.js';
|
|
7
|
-
export {
|
|
8
|
-
export { default as
|
|
9
|
-
export {
|
|
10
|
-
export {
|
|
11
|
-
export { default as
|
|
12
|
-
export {
|
|
13
|
-
export { default as
|
|
14
|
-
export {
|
|
15
|
-
export {
|
|
16
|
-
export { default as
|
|
7
|
+
export { despiaLocalPlugin } from './vite.js';
|
|
8
|
+
export { default as DespiaLocalPlugin } from './webpack.js';
|
|
9
|
+
export { despiaLocal } from './rollup.js';
|
|
10
|
+
export { withDespiaLocal } from './next.js';
|
|
11
|
+
export { default as DespiaLocalModule } from './nuxt.js';
|
|
12
|
+
export { despiaLocalSvelteKit } from './sveltekit.js';
|
|
13
|
+
export { default as despiaLocalIntegration } from './astro.js';
|
|
14
|
+
export { despiaLocalRemix } from './remix.js';
|
|
15
|
+
export { despiaLocalEsbuild } from './esbuild.js';
|
|
16
|
+
export { default as DespiaLocalParcel } from './parcel.js';
|
package/src/next.js
CHANGED
|
@@ -1,48 +1,73 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Next.js integration for generating despia/local.json manifest
|
|
3
3
|
*
|
|
4
|
-
* Usage
|
|
5
|
-
* const
|
|
6
|
-
* module.exports =
|
|
4
|
+
* Usage for static export:
|
|
5
|
+
* const withDespiaLocal = require('@despia/local/next');
|
|
6
|
+
* module.exports = withDespiaLocal({
|
|
7
7
|
* entryHtml: 'index.html',
|
|
8
|
-
* outDir: '
|
|
8
|
+
* outDir: 'out' // Next.js static export directory
|
|
9
9
|
* })({
|
|
10
|
+
* output: 'export',
|
|
10
11
|
* // your next config
|
|
11
12
|
* });
|
|
12
13
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
14
|
+
* Usage for SSR (recommended: use post-build script):
|
|
15
|
+
* // package.json
|
|
16
|
+
* {
|
|
17
|
+
* "scripts": {
|
|
18
|
+
* "build": "next build",
|
|
19
|
+
* "postbuild": "despia-local .next/static"
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* Or use the webpack plugin approach (works best for static export):
|
|
24
|
+
* const DespiaLocalPlugin = require('@despia/local/webpack');
|
|
15
25
|
* module.exports = {
|
|
16
26
|
* webpack: (config) => {
|
|
17
|
-
* config.plugins.push(new
|
|
27
|
+
* config.plugins.push(new DespiaLocalPlugin({ outDir: '.next' }));
|
|
18
28
|
* return config;
|
|
19
29
|
* }
|
|
20
30
|
* };
|
|
21
31
|
*/
|
|
22
32
|
|
|
23
33
|
import { generateManifest } from './core.js';
|
|
24
|
-
import
|
|
34
|
+
import DespiaLocalPlugin from './webpack.js';
|
|
25
35
|
|
|
26
|
-
export function
|
|
27
|
-
const
|
|
36
|
+
export function withDespiaLocal(pluginOptions = {}) {
|
|
37
|
+
const localConfig = {
|
|
28
38
|
outDir: pluginOptions.outDir || '.next',
|
|
29
39
|
entryHtml: pluginOptions.entryHtml || 'index.html',
|
|
30
40
|
...pluginOptions
|
|
31
41
|
};
|
|
32
42
|
|
|
33
43
|
return (nextConfig = {}) => {
|
|
44
|
+
// Detect if this is static export or SSR
|
|
45
|
+
const isStaticExport = nextConfig.output === 'export';
|
|
34
46
|
const existingWebpack = nextConfig.webpack;
|
|
35
47
|
|
|
36
48
|
return {
|
|
37
49
|
...nextConfig,
|
|
38
50
|
webpack: (config, options) => {
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
51
|
+
// Only add webpack plugin for client builds (not server builds)
|
|
52
|
+
// For SSR, the webpack plugin will target .next/static during client build
|
|
53
|
+
// For static export, it works normally
|
|
54
|
+
if (!options.isServer) {
|
|
55
|
+
// Determine the correct output directory
|
|
56
|
+
let targetOutDir = localConfig.outDir;
|
|
57
|
+
|
|
58
|
+
// For SSR apps, target .next/static where client assets are stored
|
|
59
|
+
if (!isStaticExport && targetOutDir === '.next') {
|
|
60
|
+
targetOutDir = '.next/static';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
config.plugins.push(
|
|
64
|
+
new DespiaLocalPlugin({
|
|
65
|
+
outDir: targetOutDir,
|
|
66
|
+
entryHtml: localConfig.entryHtml,
|
|
67
|
+
skipEntryHtml: !isStaticExport // Skip entryHtml for SSR
|
|
68
|
+
})
|
|
69
|
+
);
|
|
70
|
+
}
|
|
46
71
|
|
|
47
72
|
// Call existing webpack config if present
|
|
48
73
|
if (typeof existingWebpack === 'function') {
|
|
@@ -56,4 +81,4 @@ export function withDespiaOffline(pluginOptions = {}) {
|
|
|
56
81
|
}
|
|
57
82
|
|
|
58
83
|
// Also export as CommonJS for Next.js compatibility
|
|
59
|
-
export default
|
|
84
|
+
export default withDespiaLocal;
|
package/src/nuxt.js
CHANGED
|
@@ -4,24 +4,24 @@
|
|
|
4
4
|
* Usage in nuxt.config.js:
|
|
5
5
|
* export default {
|
|
6
6
|
* modules: ['@despia/local/nuxt'],
|
|
7
|
-
*
|
|
7
|
+
* despiaLocal: {
|
|
8
8
|
* entryHtml: 'index.html'
|
|
9
9
|
* }
|
|
10
10
|
* }
|
|
11
11
|
*
|
|
12
12
|
* Or use as a Nuxt module in modules/ directory:
|
|
13
|
-
* // modules/despia-
|
|
14
|
-
* import
|
|
15
|
-
* export default
|
|
13
|
+
* // modules/despia-local.js
|
|
14
|
+
* import DespiaLocalModule from '@despia/local/nuxt';
|
|
15
|
+
* export default DespiaLocalModule;
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { generateManifest } from './core.js';
|
|
19
19
|
|
|
20
|
-
export default function
|
|
20
|
+
export default function DespiaLocalModule(moduleOptions) {
|
|
21
21
|
const options = {
|
|
22
22
|
entryHtml: 'index.html',
|
|
23
23
|
...moduleOptions,
|
|
24
|
-
...(this.options?.
|
|
24
|
+
...(this.options?.despiaLocal || {})
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
// Hook into Nuxt build completion
|
package/src/parcel.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* "scripts": {
|
|
8
8
|
* "build": "parcel build",
|
|
9
|
-
* "postbuild": "despia-
|
|
9
|
+
* "postbuild": "despia-local dist"
|
|
10
10
|
* }
|
|
11
11
|
*
|
|
12
12
|
* For Parcel 1.x, you can use this plugin, but the API may vary.
|
|
@@ -19,7 +19,7 @@ export default function(api) {
|
|
|
19
19
|
const { outDir = 'dist', entryHtml = 'index.html' } = api.options || {};
|
|
20
20
|
|
|
21
21
|
return {
|
|
22
|
-
name: 'despia-
|
|
22
|
+
name: 'despia-local',
|
|
23
23
|
async bundleEnd({ bundleGraph }) {
|
|
24
24
|
const additionalPaths = [];
|
|
25
25
|
|
|
@@ -43,7 +43,7 @@ export default function(api) {
|
|
|
43
43
|
console.log(`✓ Generated despia/local.json with ${paths.length} assets`);
|
|
44
44
|
} catch (error) {
|
|
45
45
|
console.error('Error generating despia/local.json:', error.message);
|
|
46
|
-
console.warn('💡 Tip: For Parcel projects, use the standalone CLI: "despia-
|
|
46
|
+
console.warn('💡 Tip: For Parcel projects, use the standalone CLI: "despia-local dist"');
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
};
|
package/src/remix.js
CHANGED
|
@@ -3,23 +3,23 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Usage in remix.config.js or vite.config.js:
|
|
5
5
|
* import { remix } from '@remix-run/dev';
|
|
6
|
-
* import {
|
|
6
|
+
* import { despiaLocalRemix } from '@despia/local/remix';
|
|
7
7
|
*
|
|
8
8
|
* export default {
|
|
9
9
|
* plugins: [
|
|
10
10
|
* remix(),
|
|
11
|
-
*
|
|
11
|
+
* despiaLocalRemix({ entryHtml: 'index.html' })
|
|
12
12
|
* ]
|
|
13
13
|
* }
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { generateManifest } from './core.js';
|
|
17
17
|
|
|
18
|
-
export function
|
|
18
|
+
export function despiaLocalRemix(options = {}) {
|
|
19
19
|
const { entryHtml = 'index.html', outDir = 'build/client' } = options;
|
|
20
20
|
|
|
21
21
|
return {
|
|
22
|
-
name: 'despia-
|
|
22
|
+
name: 'despia-local-remix',
|
|
23
23
|
apply: 'build',
|
|
24
24
|
buildEnd() {
|
|
25
25
|
// Remix outputs to build/client for client assets
|
package/src/rollup.js
CHANGED
|
@@ -10,11 +10,11 @@ import { generateManifest } from './core.js';
|
|
|
10
10
|
* @param {string} options.outDir - Output directory (default: 'dist')
|
|
11
11
|
* @param {string} options.entryHtml - Entry HTML file (default: 'index.html')
|
|
12
12
|
*/
|
|
13
|
-
export function
|
|
13
|
+
export function despiaLocal(options = {}) {
|
|
14
14
|
const { outDir = 'dist', entryHtml = 'index.html' } = options;
|
|
15
15
|
|
|
16
16
|
return {
|
|
17
|
-
name: 'despia-
|
|
17
|
+
name: 'despia-local',
|
|
18
18
|
writeBundle(outputOptions, bundle) {
|
|
19
19
|
const outputDir = outputOptions.dir || outDir;
|
|
20
20
|
const additionalPaths = [];
|
package/src/sveltekit.js
CHANGED
|
@@ -3,23 +3,23 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Usage in vite.config.js:
|
|
5
5
|
* import { sveltekit } from '@sveltejs/kit/vite';
|
|
6
|
-
* import {
|
|
6
|
+
* import { despiaLocalSvelteKit } from '@despia/local/sveltekit';
|
|
7
7
|
*
|
|
8
8
|
* export default {
|
|
9
9
|
* plugins: [
|
|
10
10
|
* sveltekit(),
|
|
11
|
-
*
|
|
11
|
+
* despiaLocalSvelteKit({ entryHtml: 'index.html' })
|
|
12
12
|
* ]
|
|
13
13
|
* }
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { generateManifest } from './core.js';
|
|
17
17
|
|
|
18
|
-
export function
|
|
18
|
+
export function despiaLocalSvelteKit(options = {}) {
|
|
19
19
|
const { entryHtml = 'index.html' } = options;
|
|
20
20
|
|
|
21
21
|
return {
|
|
22
|
-
name: 'despia-
|
|
22
|
+
name: 'despia-local-sveltekit',
|
|
23
23
|
apply: 'build',
|
|
24
24
|
buildEnd() {
|
|
25
25
|
// SvelteKit outputs to build directory
|
package/src/turbopack.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import { generateManifest } from './core.js';
|
|
8
8
|
|
|
9
|
-
export function
|
|
9
|
+
export function despiaLocalTurbopack(options = {}) {
|
|
10
10
|
const { entryHtml = 'index.html', outDir = '.next' } = options;
|
|
11
11
|
|
|
12
12
|
// Turbopack is used by Next.js, so we recommend using the Next.js integration
|
|
@@ -14,7 +14,7 @@ export function despiaOfflineTurbopack(options = {}) {
|
|
|
14
14
|
console.warn('⚠ Turbopack: Use @despia/local/next instead for Next.js projects');
|
|
15
15
|
|
|
16
16
|
return {
|
|
17
|
-
name: 'despia-
|
|
17
|
+
name: 'despia-local-turbopack',
|
|
18
18
|
// Implementation would go here when Turbopack plugin API is stable
|
|
19
19
|
};
|
|
20
20
|
}
|
package/src/vite.js
CHANGED
|
@@ -11,11 +11,11 @@ import { generateManifest } from './core.js';
|
|
|
11
11
|
* @param {string} options.outDir - Output directory (default: 'dist')
|
|
12
12
|
* @param {string} options.entryHtml - Entry HTML file (default: 'index.html')
|
|
13
13
|
*/
|
|
14
|
-
export function
|
|
14
|
+
export function despiaLocalPlugin(options = {}) {
|
|
15
15
|
const { outDir = 'dist', entryHtml = 'index.html' } = options;
|
|
16
16
|
|
|
17
17
|
return {
|
|
18
|
-
name: 'despia-
|
|
18
|
+
name: 'despia-local',
|
|
19
19
|
apply: 'build',
|
|
20
20
|
writeBundle(bundleOptions, bundle) {
|
|
21
21
|
const outputDir = bundleOptions.dir || outDir;
|
package/src/webpack.js
CHANGED
|
@@ -4,19 +4,33 @@
|
|
|
4
4
|
|
|
5
5
|
import { generateManifest } from './core.js';
|
|
6
6
|
|
|
7
|
-
class
|
|
7
|
+
class DespiaLocalPlugin {
|
|
8
8
|
constructor(options = {}) {
|
|
9
9
|
this.options = {
|
|
10
10
|
outDir: options.outDir || 'dist',
|
|
11
11
|
entryHtml: options.entryHtml || 'index.html',
|
|
12
|
+
skipEntryHtml: options.skipEntryHtml || false,
|
|
12
13
|
...options
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
apply(compiler) {
|
|
17
|
-
const pluginName = '
|
|
18
|
+
const pluginName = 'DespiaLocalPlugin';
|
|
18
19
|
|
|
19
20
|
compiler.hooks.afterEmit.tapAsync(pluginName, (compilation, callback) => {
|
|
21
|
+
// Detect if this is a Next.js server build
|
|
22
|
+
// Next.js server builds have specific compiler name patterns
|
|
23
|
+
const compilerName = compilation.compiler.name || '';
|
|
24
|
+
const isNextJsServerBuild = compilerName.includes('server') ||
|
|
25
|
+
compilerName.includes('Server') ||
|
|
26
|
+
compilation.compiler.options?.target === 'node';
|
|
27
|
+
|
|
28
|
+
// Skip manifest generation for server builds (SSR apps don't need server-side assets)
|
|
29
|
+
if (isNextJsServerBuild) {
|
|
30
|
+
callback();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
20
34
|
// Get output path from webpack compiler
|
|
21
35
|
const outputPath = compilation.compiler.outputPath || this.options.outDir;
|
|
22
36
|
const additionalPaths = [];
|
|
@@ -41,7 +55,8 @@ class DespiaOfflinePlugin {
|
|
|
41
55
|
const paths = generateManifest({
|
|
42
56
|
outputDir: outputPath,
|
|
43
57
|
entryHtml: this.options.entryHtml,
|
|
44
|
-
additionalPaths
|
|
58
|
+
additionalPaths,
|
|
59
|
+
skipEntryHtml: this.options.skipEntryHtml
|
|
45
60
|
});
|
|
46
61
|
console.log(`✓ Generated despia/local.json with ${paths.length} assets`);
|
|
47
62
|
} catch (error) {
|
|
@@ -53,4 +68,4 @@ class DespiaOfflinePlugin {
|
|
|
53
68
|
}
|
|
54
69
|
}
|
|
55
70
|
|
|
56
|
-
export default
|
|
71
|
+
export default DespiaLocalPlugin;
|