svelte-bundle 0.0.1 → 0.0.21
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 +14 -17
- package/bundle.js +74 -23
- package/cli.js +59 -26
- package/package.json +27 -4
package/ReadMe.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## Usage
|
|
2
|
+
This tool can be used with `npx`:
|
|
3
|
+
```bash
|
|
4
|
+
npx svelte-bundle -i <input-dir> -o <output-dir>
|
|
5
|
+
```
|
|
6
|
+
|
|
1
7
|
# Svelte Bundle CLI
|
|
2
8
|
|
|
3
9
|
**Svelte Bundle CLI** is a simple command-line tool that allows you to bundle a Svelte application into a single `.html` file using Vite and SSR (Server-Side Rendering). The goal of this tool is to make it easy to bundle Svelte apps for deployment, particularly for cases where everything needs to be contained in a single file.
|
|
@@ -19,20 +25,11 @@ So, I searched for tools around that could be of assistance. I found [figsvelte]
|
|
|
19
25
|
|
|
20
26
|
I noticed through a lot of google searches I wasn't the only one looking for a solution like this, yet, I was unable to find one that addressed everything I was looking for. So, for this reason I have decided to build svelte-bundle to take care of this in a much more simplistic and CLI way.
|
|
21
27
|
|
|
22
|
-
## Features
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
- [
|
|
29
|
-
- [
|
|
30
|
-
- [ ] Implement error handling and more robust validation.
|
|
31
|
-
- [ ] Add support for environment-specific builds (development/production).
|
|
32
|
-
- [ ] Documentation and guides on using the tool with different Svelte apps.
|
|
33
|
-
- [ ] Tests and CI integration.
|
|
34
|
-
|
|
35
|
-
## Installation (Planned)
|
|
36
|
-
Once the tool is published on npm, it will be available via `npx`:
|
|
37
|
-
```bash
|
|
38
|
-
npx svelte-bundle -i <input-dir> -o <output-dir>
|
|
28
|
+
## Features
|
|
29
|
+
- [x] Bundles Svelte applications
|
|
30
|
+
- [x] Outputs a single `.html` file ready for deployment.
|
|
31
|
+
- [x] CLI arguments for specifying input and output directories.
|
|
32
|
+
- [x] Tests and CI integration.
|
|
33
|
+
- [x] Handle CSS and assets within the bundled file.
|
|
34
|
+
- [x] Add tailwindcss support, **this is in beta**.
|
|
35
|
+
- [x] Implement error handling and more robust validation.
|
package/bundle.js
CHANGED
|
@@ -1,17 +1,68 @@
|
|
|
1
|
+
// bundle.js
|
|
1
2
|
import fs from 'fs/promises';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import { rollup } from 'rollup';
|
|
4
5
|
import svelte from 'rollup-plugin-svelte';
|
|
5
6
|
import resolve from '@rollup/plugin-node-resolve';
|
|
6
7
|
import commonjs from '@rollup/plugin-commonjs';
|
|
7
|
-
import { compile } from 'svelte/compiler';
|
|
8
8
|
import css from 'rollup-plugin-css-only';
|
|
9
9
|
import terser from '@rollup/plugin-terser';
|
|
10
|
+
import postcss from 'postcss';
|
|
11
|
+
import tailwindcss from 'tailwindcss';
|
|
12
|
+
import autoprefixer from 'autoprefixer';
|
|
13
|
+
import cssnano from 'cssnano';
|
|
14
|
+
|
|
15
|
+
export async function buildStaticFile(svelteFilePath, outputDir, options = {}) {
|
|
16
|
+
const { useTailwind = false, tailwindConfig = null } = options;
|
|
10
17
|
|
|
11
|
-
export async function buildStaticFile(svelteFilePath, outputDir) {
|
|
12
18
|
try {
|
|
19
|
+
// Ensure output directory exists
|
|
20
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
21
|
+
|
|
13
22
|
let cssText = '';
|
|
14
23
|
|
|
24
|
+
// Setup PostCSS plugins based on whether Tailwind is enabled
|
|
25
|
+
const postcssPlugins = useTailwind
|
|
26
|
+
? [
|
|
27
|
+
tailwindcss(tailwindConfig || {
|
|
28
|
+
content: [svelteFilePath],
|
|
29
|
+
theme: { extend: {} },
|
|
30
|
+
plugins: [],
|
|
31
|
+
}),
|
|
32
|
+
autoprefixer(),
|
|
33
|
+
cssnano({
|
|
34
|
+
preset: ['default', {
|
|
35
|
+
discardComments: {
|
|
36
|
+
removeAll: true,
|
|
37
|
+
},
|
|
38
|
+
}],
|
|
39
|
+
})
|
|
40
|
+
]
|
|
41
|
+
: [
|
|
42
|
+
autoprefixer(),
|
|
43
|
+
cssnano({
|
|
44
|
+
preset: ['default', {
|
|
45
|
+
discardComments: {
|
|
46
|
+
removeAll: true,
|
|
47
|
+
},
|
|
48
|
+
}],
|
|
49
|
+
})
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
// Process global styles
|
|
53
|
+
let globalCssText = '';
|
|
54
|
+
if (useTailwind) {
|
|
55
|
+
const tailwindCss = `
|
|
56
|
+
@tailwind base;
|
|
57
|
+
@tailwind components;
|
|
58
|
+
@tailwind utilities;
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
const processedCss = await postcss(postcssPlugins)
|
|
62
|
+
.process(tailwindCss, { from: undefined });
|
|
63
|
+
globalCssText = processedCss.css;
|
|
64
|
+
}
|
|
65
|
+
|
|
15
66
|
// Create temporary SSR bundle
|
|
16
67
|
const ssrBundle = await rollup({
|
|
17
68
|
input: svelteFilePath,
|
|
@@ -22,7 +73,15 @@ export async function buildStaticFile(svelteFilePath, outputDir) {
|
|
|
22
73
|
hydratable: true,
|
|
23
74
|
css: false
|
|
24
75
|
},
|
|
25
|
-
emitCss: true
|
|
76
|
+
emitCss: true,
|
|
77
|
+
preprocess: useTailwind ? {
|
|
78
|
+
style: async ({ content }) => {
|
|
79
|
+
if (!content) return { code: '' };
|
|
80
|
+
const result = await postcss(postcssPlugins)
|
|
81
|
+
.process(content, { from: undefined });
|
|
82
|
+
return { code: result.css };
|
|
83
|
+
}
|
|
84
|
+
} : undefined
|
|
26
85
|
}),
|
|
27
86
|
css({
|
|
28
87
|
output: function(styles) {
|
|
@@ -54,7 +113,7 @@ export async function buildStaticFile(svelteFilePath, outputDir) {
|
|
|
54
113
|
const { default: App } = await import(tempSSRFile);
|
|
55
114
|
const { html: initialHtml } = App.render();
|
|
56
115
|
|
|
57
|
-
// Clean up temp
|
|
116
|
+
// Clean up temp files
|
|
58
117
|
await fs.rm(tempDir, { recursive: true, force: true });
|
|
59
118
|
|
|
60
119
|
// Build client-side bundle
|
|
@@ -66,7 +125,15 @@ export async function buildStaticFile(svelteFilePath, outputDir) {
|
|
|
66
125
|
hydratable: true,
|
|
67
126
|
css: false
|
|
68
127
|
},
|
|
69
|
-
emitCss: true
|
|
128
|
+
emitCss: true,
|
|
129
|
+
preprocess: useTailwind ? {
|
|
130
|
+
style: async ({ content }) => {
|
|
131
|
+
if (!content) return { code: '' };
|
|
132
|
+
const result = await postcss(postcssPlugins)
|
|
133
|
+
.process(content, { from: undefined });
|
|
134
|
+
return { code: result.css };
|
|
135
|
+
}
|
|
136
|
+
} : undefined
|
|
70
137
|
}),
|
|
71
138
|
css({
|
|
72
139
|
output: function(styles) {
|
|
@@ -91,29 +158,13 @@ export async function buildStaticFile(svelteFilePath, outputDir) {
|
|
|
91
158
|
});
|
|
92
159
|
|
|
93
160
|
// Create the final HTML
|
|
94
|
-
const finalHtml = `<!DOCTYPE html>
|
|
95
|
-
<html lang="en">
|
|
96
|
-
<head>
|
|
97
|
-
<meta charset="UTF-8">
|
|
98
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
99
|
-
<title>Static Svelte App</title>
|
|
100
|
-
<style>
|
|
101
|
-
${cssText}
|
|
102
|
-
</style>
|
|
103
|
-
</head>
|
|
104
|
-
<body>
|
|
105
|
-
<div id="app">${initialHtml}</div>
|
|
106
|
-
<script>
|
|
107
|
-
${clientCode}
|
|
108
|
-
const app = new App({target: document.getElementById('app'), hydrate: true});
|
|
109
|
-
</script>
|
|
110
|
-
</body>
|
|
111
|
-
</html>`;
|
|
161
|
+
const finalHtml = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Static Svelte App</title><style>${globalCssText}${cssText}</style></head><body><div id="app">${initialHtml}</div><script src="https://unpkg.com/svelte@3.58.0/internal/index.js"></script><script>${clientCode}const app=new App({target:document.getElementById("app"),hydrate:!0});</script></body></html>`;
|
|
112
162
|
|
|
113
163
|
// Write the output file
|
|
114
164
|
const outputPath = path.join(outputDir, 'output.html');
|
|
115
165
|
await fs.writeFile(outputPath, finalHtml, 'utf-8');
|
|
116
166
|
} catch (error) {
|
|
167
|
+
console.error('Build error:', error);
|
|
117
168
|
throw error;
|
|
118
169
|
}
|
|
119
170
|
}
|
package/cli.js
CHANGED
|
@@ -7,46 +7,50 @@ import { createInterface } from 'readline';
|
|
|
7
7
|
import { buildStaticFile } from './bundle.js';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
9
|
|
|
10
|
+
// Get package.json data
|
|
11
|
+
import { readFile } from 'fs/promises';
|
|
10
12
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
13
|
const __dirname = path.dirname(__filename);
|
|
12
14
|
|
|
13
|
-
//
|
|
15
|
+
// Read package.json
|
|
16
|
+
const packageJson = JSON.parse(
|
|
17
|
+
await readFile(
|
|
18
|
+
new URL('./package.json', import.meta.url)
|
|
19
|
+
)
|
|
20
|
+
);
|
|
21
|
+
|
|
14
22
|
const rl = createInterface({
|
|
15
23
|
input: process.stdin,
|
|
16
24
|
output: process.stdout
|
|
17
25
|
});
|
|
18
26
|
|
|
19
|
-
// Promisify readline question
|
|
20
27
|
const question = (query) => new Promise((resolve) => rl.question(query, resolve));
|
|
21
28
|
|
|
22
29
|
program
|
|
23
30
|
.name('svelte-bundle')
|
|
24
|
-
.description(
|
|
25
|
-
.version(
|
|
31
|
+
.description(packageJson.description)
|
|
32
|
+
.version(packageJson.version)
|
|
26
33
|
.requiredOption('-i, --input <path>', 'Input Svelte file')
|
|
27
34
|
.option('-o, --output <path>', 'Output directory (defaults to current directory)')
|
|
35
|
+
.option('--tw', 'Enable Tailwind CSS processing')
|
|
36
|
+
.option('--tw-config <path>', 'Path to custom Tailwind config file')
|
|
28
37
|
.option('-f, --force', 'Force overwrite without asking');
|
|
29
38
|
|
|
30
39
|
program.parse();
|
|
31
40
|
|
|
32
41
|
const options = program.opts();
|
|
33
42
|
|
|
34
|
-
async function
|
|
43
|
+
async function loadTailwindConfig(configPath) {
|
|
44
|
+
const fullPath = path.resolve(configPath);
|
|
35
45
|
try {
|
|
36
|
-
await
|
|
37
|
-
return
|
|
38
|
-
} catch {
|
|
39
|
-
|
|
46
|
+
const { default: config } = await import(fullPath);
|
|
47
|
+
return config;
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error(chalk.red(`Error loading Tailwind config: ${error.message}`));
|
|
50
|
+
process.exit(1);
|
|
40
51
|
}
|
|
41
52
|
}
|
|
42
53
|
|
|
43
|
-
async function shouldOverwrite(filepath) {
|
|
44
|
-
const answer = await question(
|
|
45
|
-
chalk.yellow(`File ${filepath} already exists. Overwrite? (y/N): `)
|
|
46
|
-
);
|
|
47
|
-
return answer.toLowerCase() === 'y';
|
|
48
|
-
}
|
|
49
|
-
|
|
50
54
|
async function validateAndProcess() {
|
|
51
55
|
try {
|
|
52
56
|
// Validate input file
|
|
@@ -66,21 +70,43 @@ async function validateAndProcess() {
|
|
|
66
70
|
process.exit(1);
|
|
67
71
|
}
|
|
68
72
|
|
|
69
|
-
//
|
|
73
|
+
// Handle Tailwind configuration
|
|
74
|
+
let tailwindConfig = null;
|
|
75
|
+
if (options.tw) {
|
|
76
|
+
if (options.twConfig) {
|
|
77
|
+
try {
|
|
78
|
+
tailwindConfig = await loadTailwindConfig(options.twConfig);
|
|
79
|
+
console.log(chalk.blue('Using custom Tailwind configuration'));
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error(chalk.red(`Error loading Tailwind config: ${error.message}`));
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
console.log(chalk.blue('Using default Tailwind configuration'));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Validate Tailwind config usage
|
|
90
|
+
if (options.twConfig && !options.tw) {
|
|
91
|
+
console.error(chalk.yellow('Warning: Tailwind config provided but Tailwind is not enabled. Use --tw to enable Tailwind.'));
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Determine output directory
|
|
70
96
|
let outputDir = process.cwd();
|
|
71
97
|
if (options.output) {
|
|
72
98
|
outputDir = path.resolve(options.output);
|
|
73
|
-
// Create output directory if it doesn't exist
|
|
74
|
-
await fs.mkdir(outputDir, { recursive: true });
|
|
75
99
|
}
|
|
76
100
|
|
|
77
101
|
const outputPath = path.join(outputDir, 'output.html');
|
|
78
102
|
|
|
79
|
-
// Check if output file exists
|
|
80
|
-
if (await
|
|
103
|
+
// Check if output file exists
|
|
104
|
+
if (await fs.access(outputPath).then(() => true).catch(() => false)) {
|
|
81
105
|
if (!options.force) {
|
|
82
|
-
const shouldProceed = await
|
|
83
|
-
|
|
106
|
+
const shouldProceed = await question(
|
|
107
|
+
chalk.yellow(`File ${outputPath} already exists. Overwrite? (y/N): `)
|
|
108
|
+
);
|
|
109
|
+
if (shouldProceed.toLowerCase() !== 'y') {
|
|
84
110
|
console.log(chalk.yellow('Operation cancelled.'));
|
|
85
111
|
process.exit(0);
|
|
86
112
|
}
|
|
@@ -89,10 +115,17 @@ async function validateAndProcess() {
|
|
|
89
115
|
|
|
90
116
|
console.log(chalk.blue('Starting build process...'));
|
|
91
117
|
console.log(chalk.gray(`Input: ${inputPath}`));
|
|
92
|
-
console.log(chalk.gray(`Output: ${
|
|
118
|
+
console.log(chalk.gray(`Output directory: ${outputDir}`));
|
|
119
|
+
if (options.tw) {
|
|
120
|
+
console.log(chalk.gray('Tailwind CSS enabled'));
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const buildOptions = {
|
|
124
|
+
useTailwind: options.tw || false,
|
|
125
|
+
tailwindConfig: tailwindConfig
|
|
126
|
+
};
|
|
93
127
|
|
|
94
|
-
|
|
95
|
-
await buildStaticFile(inputPath, outputDir);
|
|
128
|
+
await buildStaticFile(inputPath, outputDir, buildOptions);
|
|
96
129
|
|
|
97
130
|
console.log(chalk.green('\n✨ Build completed successfully!'));
|
|
98
131
|
console.log(chalk.gray(`Output file: ${outputPath}`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "svelte-bundle",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.21",
|
|
4
4
|
"description": "Bundle Svelte files into static HTML files",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,10 +18,18 @@
|
|
|
18
18
|
"ssr"
|
|
19
19
|
],
|
|
20
20
|
"publishConfig": {
|
|
21
|
-
"access": "public"
|
|
21
|
+
"access": "public",
|
|
22
|
+
"registry": "https://registry.npmjs.org/"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/uhteddy/svelte-bundle.git"
|
|
22
27
|
},
|
|
23
28
|
"scripts": {
|
|
24
|
-
"prepublishOnly": "chmod +x cli.js"
|
|
29
|
+
"prepublishOnly": "chmod +x cli.js",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"test:watch": "vitest",
|
|
32
|
+
"test:coverage": "vitest run --coverage"
|
|
25
33
|
},
|
|
26
34
|
"author": "Teddy Hartling",
|
|
27
35
|
"license": "MIT",
|
|
@@ -29,11 +37,26 @@
|
|
|
29
37
|
"@rollup/plugin-commonjs": "^24.0.1",
|
|
30
38
|
"@rollup/plugin-node-resolve": "^15.0.2",
|
|
31
39
|
"@rollup/plugin-terser": "^0.4.0",
|
|
40
|
+
"autoprefixer": "^10.4.20",
|
|
32
41
|
"chalk": "^5.3.0",
|
|
33
42
|
"commander": "^11.0.0",
|
|
43
|
+
"cssnano": "^7.0.6",
|
|
34
44
|
"rollup": "^3.20.0",
|
|
35
45
|
"rollup-plugin-css-only": "^4.3.0",
|
|
46
|
+
"rollup-plugin-postcss": "^4.0.2",
|
|
36
47
|
"rollup-plugin-svelte": "^7.1.4",
|
|
37
|
-
"svelte": "^3.58.0"
|
|
48
|
+
"svelte": "^3.58.0",
|
|
49
|
+
"tailwindcss": "^3.4.14"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@vitest/coverage-v8": "^2.1.3",
|
|
53
|
+
"vitest": "^2.1.3"
|
|
54
|
+
},
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/uhteddy/svelte-bundle/issues"
|
|
57
|
+
},
|
|
58
|
+
"homepage": "https://github.com/uhteddy/svelte-bundle#readme",
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=18"
|
|
38
61
|
}
|
|
39
62
|
}
|