@despia/local 1.0.2 → 1.0.4
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 +16 -120
- package/generate-offline-manifest.js +58 -6
- package/package.json +2 -6
- package/src/core.js +14 -7
- package/src/webpack.js +113 -30
- package/src/next.js +0 -84
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Universal build plugin to generate `despia/local.json` manifest for [Despia](htt
|
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- **Universal Support** - Works with Vite, Webpack, Rollup,
|
|
11
|
+
- **Universal Support** - Works with Vite, Webpack, Rollup, Nuxt, SvelteKit, Astro, Remix, esbuild, Parcel, and more
|
|
12
12
|
- **Zero Dependencies** - Uses only Node.js built-in modules
|
|
13
13
|
- **Automatic Asset Discovery** - Collects all output files (JS, CSS, images, fonts, HTML, etc.)
|
|
14
14
|
- **Root-Relative Paths** - Formats all paths as root-relative (starting with `/`)
|
|
@@ -343,7 +343,21 @@ Add to your `package.json`:
|
|
|
343
343
|
Or run manually:
|
|
344
344
|
|
|
345
345
|
```bash
|
|
346
|
-
npx despia-local [outputDir] [entryHtml]
|
|
346
|
+
npx despia-local [outputDir] [entryHtml] [--output|-o manifestPath]
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**Options:**
|
|
350
|
+
- `--output`, `-o <path>` - Custom output path for manifest file (useful for hosting providers)
|
|
351
|
+
- `--help`, `-h` - Show help message
|
|
352
|
+
|
|
353
|
+
**Examples:**
|
|
354
|
+
```bash
|
|
355
|
+
# Default: generates manifest in outputDir/despia/local.json
|
|
356
|
+
npx despia-local dist
|
|
357
|
+
|
|
358
|
+
# Custom output location (e.g., for Vercel/Netlify)
|
|
359
|
+
npx despia-local dist --output public/despia/local.json
|
|
360
|
+
npx despia-local build -o public/manifest.json
|
|
347
361
|
```
|
|
348
362
|
|
|
349
363
|
## Framework Support
|
|
@@ -416,100 +430,6 @@ export default {
|
|
|
416
430
|
};
|
|
417
431
|
```
|
|
418
432
|
|
|
419
|
-
### Next.js
|
|
420
|
-
|
|
421
|
-
**For static export (recommended for static sites):**
|
|
422
|
-
|
|
423
|
-
```javascript
|
|
424
|
-
// next.config.js
|
|
425
|
-
const withDespiaLocal = require('@despia/local/next');
|
|
426
|
-
|
|
427
|
-
module.exports = withDespiaLocal({
|
|
428
|
-
entryHtml: 'index.html',
|
|
429
|
-
outDir: 'out' // Next.js static export directory
|
|
430
|
-
})({
|
|
431
|
-
output: 'export',
|
|
432
|
-
// your Next.js config
|
|
433
|
-
});
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
**For static export (alternative):**
|
|
437
|
-
|
|
438
|
-
```javascript
|
|
439
|
-
// next.config.js
|
|
440
|
-
const withDespiaLocal = require('@despia/local/next');
|
|
441
|
-
|
|
442
|
-
module.exports = withDespiaLocal({
|
|
443
|
-
outDir: 'out', // Next.js static export directory
|
|
444
|
-
entryHtml: 'index.html'
|
|
445
|
-
})({
|
|
446
|
-
output: 'export',
|
|
447
|
-
// ... rest of config
|
|
448
|
-
});
|
|
449
|
-
```
|
|
450
|
-
|
|
451
|
-
**Alternative: Webpack Plugin Approach (works best for static export):**
|
|
452
|
-
|
|
453
|
-
```javascript
|
|
454
|
-
// next.config.js
|
|
455
|
-
const DespiaLocalPlugin = require('@despia/local/webpack');
|
|
456
|
-
|
|
457
|
-
module.exports = {
|
|
458
|
-
output: 'export', // For static export
|
|
459
|
-
webpack: (config) => {
|
|
460
|
-
config.plugins.push(
|
|
461
|
-
new DespiaLocalPlugin({ outDir: 'out' })
|
|
462
|
-
);
|
|
463
|
-
return config;
|
|
464
|
-
}
|
|
465
|
-
};
|
|
466
|
-
```
|
|
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
|
-
|
|
513
433
|
### Nuxt
|
|
514
434
|
|
|
515
435
|
```javascript
|
|
@@ -782,30 +702,6 @@ The generated manifest is then used by Despia during app hydration and updates t
|
|
|
782
702
|
- Paths starting with `/` are preserved as-is
|
|
783
703
|
- Windows backslashes are converted to forward slashes
|
|
784
704
|
|
|
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
|
-
|
|
809
705
|
## Contributing
|
|
810
706
|
|
|
811
707
|
Contributions welcome! Please open an issue or submit a pull request.
|
|
@@ -5,21 +5,64 @@
|
|
|
5
5
|
* Can be used with any build system by running after build completes
|
|
6
6
|
*
|
|
7
7
|
* Usage:
|
|
8
|
-
* node generate-offline-manifest.js [outputDir] [entryHtml]
|
|
8
|
+
* node generate-offline-manifest.js [outputDir] [entryHtml] [--output|-o manifestPath]
|
|
9
9
|
*
|
|
10
10
|
* Examples:
|
|
11
11
|
* node generate-offline-manifest.js
|
|
12
12
|
* node generate-offline-manifest.js dist
|
|
13
13
|
* node generate-offline-manifest.js dist index.html
|
|
14
|
+
* node generate-offline-manifest.js .next/static --output public/despia/local.json
|
|
15
|
+
* node generate-offline-manifest.js dist -o public/despia/local.json
|
|
14
16
|
*/
|
|
15
17
|
|
|
16
18
|
import { generateManifest } from './src/core.js';
|
|
17
19
|
import { resolve, join } from 'path';
|
|
18
20
|
import { existsSync } from 'fs';
|
|
19
21
|
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
// Parse command line arguments
|
|
23
|
+
let outputDir = 'dist';
|
|
24
|
+
let entryHtml = 'index.html';
|
|
25
|
+
let manifestOutputPath = null;
|
|
26
|
+
|
|
27
|
+
// Check for --help flag
|
|
28
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
29
|
+
console.log(`
|
|
30
|
+
Usage: despia-local [outputDir] [entryHtml] [options]
|
|
31
|
+
|
|
32
|
+
Arguments:
|
|
33
|
+
outputDir Directory to scan for assets (default: 'dist')
|
|
34
|
+
entryHtml Entry HTML filename (default: 'index.html')
|
|
35
|
+
|
|
36
|
+
Options:
|
|
37
|
+
--output, -o <path> Custom output path for manifest file
|
|
38
|
+
--help, -h Show this help message
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
despia-local
|
|
42
|
+
despia-local dist
|
|
43
|
+
despia-local dist index.html
|
|
44
|
+
despia-local .next/static --output public/despia/local.json
|
|
45
|
+
despia-local dist -o public/manifest.json
|
|
46
|
+
`);
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Parse arguments
|
|
51
|
+
for (let i = 2; i < process.argv.length; i++) {
|
|
52
|
+
const arg = process.argv[i];
|
|
53
|
+
|
|
54
|
+
if (arg === '--output' || arg === '-o') {
|
|
55
|
+
manifestOutputPath = process.argv[++i];
|
|
56
|
+
if (!manifestOutputPath) {
|
|
57
|
+
console.error('❌ Error: --output/-o requires a path argument');
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
} else if (outputDir === 'dist' && !arg.startsWith('-')) {
|
|
61
|
+
outputDir = arg;
|
|
62
|
+
} else if (!arg.startsWith('-') && entryHtml === 'index.html' && manifestOutputPath === null) {
|
|
63
|
+
entryHtml = arg;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
23
66
|
|
|
24
67
|
// Detect Next.js SSR context
|
|
25
68
|
const isNextJsDir = outputDir.includes('.next');
|
|
@@ -68,16 +111,25 @@ try {
|
|
|
68
111
|
const paths = generateManifest({
|
|
69
112
|
outputDir,
|
|
70
113
|
entryHtml,
|
|
71
|
-
skipEntryHtml
|
|
114
|
+
skipEntryHtml,
|
|
115
|
+
manifestOutputPath
|
|
72
116
|
});
|
|
73
117
|
|
|
74
|
-
|
|
118
|
+
const manifestLocation = manifestOutputPath || join(outputDir, 'despia', 'local.json');
|
|
119
|
+
console.log(`✓ Generated ${manifestLocation}`);
|
|
75
120
|
console.log(`✓ Included ${paths.length} assets`);
|
|
76
121
|
if (!skipEntryHtml) {
|
|
77
122
|
console.log(`✓ Entry HTML: /${entryHtml}`);
|
|
78
123
|
} else {
|
|
79
124
|
console.log(`✓ Skipped entry HTML (SSR mode)`);
|
|
80
125
|
}
|
|
126
|
+
|
|
127
|
+
// Provide helpful hint if using default location for Next.js SSR
|
|
128
|
+
if (isNextJsStatic && !manifestOutputPath) {
|
|
129
|
+
console.log('');
|
|
130
|
+
console.log('💡 Tip: For hosting providers (Vercel, Netlify, etc.), consider using:');
|
|
131
|
+
console.log(` despia-local .next/static --output public/despia/local.json`);
|
|
132
|
+
}
|
|
81
133
|
} catch (error) {
|
|
82
134
|
console.error(`❌ Error: ${error.message}`);
|
|
83
135
|
console.error('💡 Please run this script after your build completes.');
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@despia/local",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Universal build plugin to generate despia/local.json manifest for offline caching in Despia web-native apps. Supports Vite, Webpack, Rollup,
|
|
3
|
+
"version": "1.0.4",
|
|
4
|
+
"description": "Universal build plugin to generate despia/local.json manifest for offline caching in Despia web-native apps. Supports Vite, Webpack, Rollup, Nuxt, SvelteKit, Astro, Remix, esbuild, Parcel, and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/core.js",
|
|
7
7
|
"bin": {
|
|
@@ -20,9 +20,6 @@
|
|
|
20
20
|
"./rollup": {
|
|
21
21
|
"import": "./src/rollup.js"
|
|
22
22
|
},
|
|
23
|
-
"./next": {
|
|
24
|
-
"import": "./src/next.js"
|
|
25
|
-
},
|
|
26
23
|
"./nuxt": {
|
|
27
24
|
"import": "./src/nuxt.js"
|
|
28
25
|
},
|
|
@@ -67,7 +64,6 @@
|
|
|
67
64
|
"vite",
|
|
68
65
|
"webpack",
|
|
69
66
|
"rollup",
|
|
70
|
-
"nextjs",
|
|
71
67
|
"nuxt",
|
|
72
68
|
"sveltekit",
|
|
73
69
|
"astro",
|
package/src/core.js
CHANGED
|
@@ -48,15 +48,20 @@ export function collectFiles(dir, baseDir = dir) {
|
|
|
48
48
|
/**
|
|
49
49
|
* Generate the offline manifest file
|
|
50
50
|
* @param {Object} options
|
|
51
|
-
* @param {string} options.outputDir - Output directory path
|
|
51
|
+
* @param {string} options.outputDir - Output directory path (where to scan for assets)
|
|
52
52
|
* @param {string} options.entryHtml - Entry HTML filename (default: 'index.html')
|
|
53
53
|
* @param {string[]} options.additionalPaths - Additional paths to include
|
|
54
54
|
* @param {boolean} options.skipEntryHtml - Skip adding entry HTML to manifest (for SSR apps)
|
|
55
|
+
* @param {string} options.manifestOutputPath - Custom path for manifest file (default: outputDir/despia/local.json)
|
|
55
56
|
* @returns {string[]} Array of all asset paths
|
|
56
57
|
*/
|
|
57
|
-
export function generateManifest({ outputDir, entryHtml = 'index.html', additionalPaths = [], skipEntryHtml = false }) {
|
|
58
|
+
export function generateManifest({ outputDir, entryHtml = 'index.html', additionalPaths = [], skipEntryHtml = false, manifestOutputPath = null }) {
|
|
58
59
|
const outputPath = resolve(process.cwd(), outputDir);
|
|
59
|
-
|
|
60
|
+
|
|
61
|
+
// Use custom manifest output path if provided, otherwise default to outputDir/despia/local.json
|
|
62
|
+
const manifestPath = manifestOutputPath
|
|
63
|
+
? resolve(process.cwd(), manifestOutputPath)
|
|
64
|
+
: join(outputPath, 'despia', 'local.json');
|
|
60
65
|
|
|
61
66
|
// Check if output directory exists
|
|
62
67
|
if (!existsSync(outputPath)) {
|
|
@@ -83,10 +88,12 @@ export function generateManifest({ outputDir, entryHtml = 'index.html', addition
|
|
|
83
88
|
// Convert to sorted array
|
|
84
89
|
const sortedPaths = Array.from(assetPaths).sort();
|
|
85
90
|
|
|
86
|
-
// Create
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
// Create directory for manifest if it doesn't exist
|
|
92
|
+
const manifestDir = manifestOutputPath
|
|
93
|
+
? resolve(manifestPath, '..')
|
|
94
|
+
: join(outputPath, 'despia');
|
|
95
|
+
if (!existsSync(manifestDir)) {
|
|
96
|
+
mkdirSync(manifestDir, { recursive: true });
|
|
90
97
|
}
|
|
91
98
|
|
|
92
99
|
// Write formatted JSON array
|
package/src/webpack.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { generateManifest } from './core.js';
|
|
6
|
+
import { readdirSync } from 'fs';
|
|
7
|
+
import { join, relative, extname } from 'path';
|
|
6
8
|
|
|
7
9
|
class DespiaLocalPlugin {
|
|
8
10
|
constructor(options = {}) {
|
|
@@ -10,20 +12,57 @@ class DespiaLocalPlugin {
|
|
|
10
12
|
outDir: options.outDir || 'dist',
|
|
11
13
|
entryHtml: options.entryHtml || 'index.html',
|
|
12
14
|
skipEntryHtml: options.skipEntryHtml || false,
|
|
15
|
+
extensions: options.extensions || ['.js', '.css', '.mjs', '.woff', '.woff2', '.ttf', '.eot', '.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.ico', '.json', '.xml', '.txt'],
|
|
16
|
+
publicDir: options.publicDir || null,
|
|
13
17
|
...options
|
|
14
18
|
};
|
|
15
19
|
}
|
|
16
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Scan public directory for static assets
|
|
23
|
+
*/
|
|
24
|
+
scanPublicDir(dir, baseDir, assets) {
|
|
25
|
+
try {
|
|
26
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
27
|
+
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
const fullPath = join(dir, entry.name);
|
|
30
|
+
|
|
31
|
+
if (entry.isDirectory()) {
|
|
32
|
+
// Skip despia folder to avoid circular reference
|
|
33
|
+
if (entry.name !== 'despia') {
|
|
34
|
+
this.scanPublicDir(fullPath, baseDir, assets);
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
const ext = extname(entry.name).toLowerCase();
|
|
38
|
+
if (this.options.extensions.includes(ext)) {
|
|
39
|
+
const relativePath = '/' + relative(baseDir, fullPath).replace(/\\/g, '/');
|
|
40
|
+
assets.add(relativePath);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} catch (e) {
|
|
45
|
+
// Ignore permission errors
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
17
49
|
apply(compiler) {
|
|
18
50
|
const pluginName = 'DespiaLocalPlugin';
|
|
51
|
+
const isNextJs = this.options.isNextJs || false;
|
|
52
|
+
const injectIntoAssets = this.options.injectIntoAssets || false;
|
|
53
|
+
|
|
54
|
+
// For Next.js: Use 'emit' phase to inject into compilation.assets
|
|
55
|
+
// For other bundlers: Use 'afterEmit' phase to write to filesystem
|
|
56
|
+
const hook = injectIntoAssets ? compiler.hooks.emit : compiler.hooks.afterEmit;
|
|
19
57
|
|
|
20
|
-
|
|
58
|
+
hook.tapAsync(pluginName, (compilation, callback) => {
|
|
21
59
|
// Detect if this is a Next.js server build
|
|
22
60
|
// Next.js server builds have specific compiler name patterns
|
|
23
61
|
const compilerName = compilation.compiler.name || '';
|
|
24
|
-
const isNextJsServerBuild = compilerName.includes('server') ||
|
|
62
|
+
const isNextJsServerBuild = (compilerName.includes('server') ||
|
|
25
63
|
compilerName.includes('Server') ||
|
|
26
|
-
compilation.compiler.options?.target === 'node'
|
|
64
|
+
compilation.compiler.options?.target === 'node') &&
|
|
65
|
+
isNextJs;
|
|
27
66
|
|
|
28
67
|
// Skip manifest generation for server builds (SSR apps don't need server-side assets)
|
|
29
68
|
if (isNextJsServerBuild) {
|
|
@@ -31,36 +70,80 @@ class DespiaLocalPlugin {
|
|
|
31
70
|
return;
|
|
32
71
|
}
|
|
33
72
|
|
|
34
|
-
|
|
35
|
-
const outputPath = compilation.compiler.outputPath || this.options.outDir;
|
|
36
|
-
const additionalPaths = [];
|
|
73
|
+
const assets = new Set();
|
|
37
74
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
75
|
+
if (injectIntoAssets && isNextJs) {
|
|
76
|
+
// Next.js mode: Collect from webpack compilation and public folder
|
|
77
|
+
|
|
78
|
+
// 1. Collect all webpack-generated assets from .next/static
|
|
79
|
+
for (const filename of Object.keys(compilation.assets)) {
|
|
80
|
+
if (filename === this.options.manifestPath) {
|
|
81
|
+
continue; // Skip the manifest file itself
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const ext = extname(filename).toLowerCase();
|
|
85
|
+
if (this.options.extensions.includes(ext)) {
|
|
86
|
+
// Next.js serves these at /_next/static/...
|
|
87
|
+
assets.add(`/_next/static/${filename}`);
|
|
88
|
+
}
|
|
43
89
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
90
|
+
|
|
91
|
+
// 2. Scan /public folder for static assets
|
|
92
|
+
if (this.options.publicDir) {
|
|
93
|
+
this.scanPublicDir(this.options.publicDir, this.options.publicDir, assets);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 3. Generate sorted array (Despia format - just a JSON array)
|
|
97
|
+
const manifest = JSON.stringify([...assets].sort(), null, 2);
|
|
98
|
+
|
|
99
|
+
// 4. Inject into webpack output at despia/local.json
|
|
100
|
+
const manifestPath = this.options.manifestPath || 'despia/local.json';
|
|
101
|
+
compilation.assets[manifestPath] = {
|
|
102
|
+
source: () => manifest,
|
|
103
|
+
size: () => Buffer.byteLength(manifest, 'utf8')
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
console.log(`✓ Injected despia/local.json into build with ${assets.size} assets`);
|
|
107
|
+
} else {
|
|
108
|
+
// Traditional mode: Write to filesystem (for other bundlers)
|
|
109
|
+
const additionalPaths = new Set();
|
|
110
|
+
|
|
111
|
+
// Collect all emitted assets from compilation
|
|
112
|
+
for (const [filename, asset] of Object.entries(compilation.assets)) {
|
|
113
|
+
if (asset && filename !== this.options.manifestPath) {
|
|
114
|
+
let rootRelativePath = filename.replace(/\\/g, '/');
|
|
115
|
+
if (!rootRelativePath.startsWith('/')) {
|
|
116
|
+
rootRelativePath = '/' + rootRelativePath;
|
|
117
|
+
}
|
|
118
|
+
additionalPaths.add(rootRelativePath);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Also collect from compilation.getAssets() if available (webpack 5)
|
|
123
|
+
if (compilation.getAssets) {
|
|
124
|
+
for (const asset of compilation.getAssets()) {
|
|
125
|
+
if (asset.name !== this.options.manifestPath) {
|
|
126
|
+
let assetPath = asset.name.replace(/\\/g, '/');
|
|
127
|
+
if (!assetPath.startsWith('/')) {
|
|
128
|
+
assetPath = '/' + assetPath;
|
|
129
|
+
}
|
|
130
|
+
additionalPaths.add(assetPath);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
try {
|
|
136
|
+
const outputPath = compilation.compiler.outputPath || this.options.outDir;
|
|
137
|
+
const paths = generateManifest({
|
|
138
|
+
outputDir: outputPath,
|
|
139
|
+
entryHtml: this.options.entryHtml,
|
|
140
|
+
additionalPaths: Array.from(additionalPaths),
|
|
141
|
+
skipEntryHtml: this.options.skipEntryHtml
|
|
142
|
+
});
|
|
143
|
+
console.log(`✓ Generated despia/local.json with ${paths.length} assets`);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error('Error generating despia/local.json:', error.message);
|
|
51
146
|
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
const paths = generateManifest({
|
|
56
|
-
outputDir: outputPath,
|
|
57
|
-
entryHtml: this.options.entryHtml,
|
|
58
|
-
additionalPaths,
|
|
59
|
-
skipEntryHtml: this.options.skipEntryHtml
|
|
60
|
-
});
|
|
61
|
-
console.log(`✓ Generated despia/local.json with ${paths.length} assets`);
|
|
62
|
-
} catch (error) {
|
|
63
|
-
console.error('Error generating despia/local.json:', error.message);
|
|
64
147
|
}
|
|
65
148
|
|
|
66
149
|
callback();
|
package/src/next.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Next.js integration for generating despia/local.json manifest
|
|
3
|
-
*
|
|
4
|
-
* Usage for static export:
|
|
5
|
-
* const withDespiaLocal = require('@despia/local/next');
|
|
6
|
-
* module.exports = withDespiaLocal({
|
|
7
|
-
* entryHtml: 'index.html',
|
|
8
|
-
* outDir: 'out' // Next.js static export directory
|
|
9
|
-
* })({
|
|
10
|
-
* output: 'export',
|
|
11
|
-
* // your next config
|
|
12
|
-
* });
|
|
13
|
-
*
|
|
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');
|
|
25
|
-
* module.exports = {
|
|
26
|
-
* webpack: (config) => {
|
|
27
|
-
* config.plugins.push(new DespiaLocalPlugin({ outDir: '.next' }));
|
|
28
|
-
* return config;
|
|
29
|
-
* }
|
|
30
|
-
* };
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
import { generateManifest } from './core.js';
|
|
34
|
-
import DespiaLocalPlugin from './webpack.js';
|
|
35
|
-
|
|
36
|
-
export function withDespiaLocal(pluginOptions = {}) {
|
|
37
|
-
const localConfig = {
|
|
38
|
-
outDir: pluginOptions.outDir || '.next',
|
|
39
|
-
entryHtml: pluginOptions.entryHtml || 'index.html',
|
|
40
|
-
...pluginOptions
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
return (nextConfig = {}) => {
|
|
44
|
-
// Detect if this is static export or SSR
|
|
45
|
-
const isStaticExport = nextConfig.output === 'export';
|
|
46
|
-
const existingWebpack = nextConfig.webpack;
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
...nextConfig,
|
|
50
|
-
webpack: (config, options) => {
|
|
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
|
-
}
|
|
71
|
-
|
|
72
|
-
// Call existing webpack config if present
|
|
73
|
-
if (typeof existingWebpack === 'function') {
|
|
74
|
-
return existingWebpack(config, options);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return config;
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Also export as CommonJS for Next.js compatibility
|
|
84
|
-
export default withDespiaLocal;
|