@webmate-studio/cli 0.1.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.
- package/bin/wm.js +102 -0
- package/package.json +37 -0
- package/src/commands/build.js +113 -0
- package/src/commands/dev.js +29 -0
- package/src/commands/generate.js +579 -0
- package/src/commands/info.js +49 -0
- package/src/commands/init.js +452 -0
- package/src/commands/login.js +193 -0
- package/src/commands/logout.js +20 -0
- package/src/commands/prop.js +286 -0
- package/src/commands/push.js +275 -0
- package/src/commands/switch.js +131 -0
- package/src/index.js +4 -0
- package/src/templates/islands/alpine.js +44 -0
- package/src/templates/islands/lit.js +90 -0
- package/src/templates/islands/preact.jsx +52 -0
- package/src/templates/islands/react.jsx +50 -0
- package/src/templates/islands/svelte-component.svelte +36 -0
- package/src/templates/islands/svelte.js +31 -0
- package/src/templates/islands/vanilla.js +71 -0
- package/src/templates/islands/vue.js +65 -0
- package/src/utils/auth.js +125 -0
- package/src/utils/bundler.js +163 -0
- package/src/utils/config.js +103 -0
- package/src/utils/semver.js +76 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import * as esbuild from 'esbuild';
|
|
2
|
+
import esbuildSvelte from 'esbuild-svelte';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import pc from 'picocolors';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Bundle island JavaScript files with esbuild
|
|
9
|
+
* Supports: Vanilla JS, React, Preact, Svelte, Alpine, Lit, Vue, Solid
|
|
10
|
+
*/
|
|
11
|
+
export async function bundleIsland(islandPath, outputPath, options = {}) {
|
|
12
|
+
const {
|
|
13
|
+
minify = true,
|
|
14
|
+
sourcemap = true,
|
|
15
|
+
target = 'es2020',
|
|
16
|
+
format = 'esm'
|
|
17
|
+
} = options;
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Resolve paths for dependencies from CLI package
|
|
21
|
+
const cliNodeModules = path.resolve(import.meta.dirname, '../../node_modules');
|
|
22
|
+
|
|
23
|
+
// Determine if this file should use JSX loader
|
|
24
|
+
// Only use JSX for .jsx files (React/Preact), not for .js files (Lit/Alpine/Vue/Vanilla)
|
|
25
|
+
const useJsxLoader = islandPath.endsWith('.jsx');
|
|
26
|
+
|
|
27
|
+
const result = await esbuild.build({
|
|
28
|
+
entryPoints: [islandPath],
|
|
29
|
+
bundle: true,
|
|
30
|
+
minify,
|
|
31
|
+
sourcemap,
|
|
32
|
+
format,
|
|
33
|
+
target,
|
|
34
|
+
outfile: outputPath,
|
|
35
|
+
platform: 'browser',
|
|
36
|
+
// Only enable JSX for .jsx files (React/Preact)
|
|
37
|
+
loader: useJsxLoader ? {
|
|
38
|
+
'.jsx': 'jsx',
|
|
39
|
+
'.ts': 'tsx',
|
|
40
|
+
'.tsx': 'tsx'
|
|
41
|
+
} : {
|
|
42
|
+
'.ts': 'tsx',
|
|
43
|
+
'.tsx': 'tsx'
|
|
44
|
+
},
|
|
45
|
+
// Use automatic JSX runtime (React 17+) only for JSX files
|
|
46
|
+
jsx: useJsxLoader ? 'automatic' : undefined,
|
|
47
|
+
// JSX import source (Preact uses preact, React uses react)
|
|
48
|
+
jsxImportSource: useJsxLoader ? 'preact' : undefined,
|
|
49
|
+
// Alias vue to the full build (with template compiler)
|
|
50
|
+
alias: {
|
|
51
|
+
'vue': 'vue/dist/vue.esm-bundler.js'
|
|
52
|
+
},
|
|
53
|
+
// Define Vue feature flags
|
|
54
|
+
define: {
|
|
55
|
+
'__VUE_OPTIONS_API__': 'true',
|
|
56
|
+
'__VUE_PROD_DEVTOOLS__': 'false',
|
|
57
|
+
'__VUE_PROD_HYDRATION_MISMATCH_DETAILS__': 'false'
|
|
58
|
+
},
|
|
59
|
+
plugins: [
|
|
60
|
+
// Svelte support
|
|
61
|
+
esbuildSvelte({
|
|
62
|
+
compilerOptions: {
|
|
63
|
+
css: 'injected' // Inject CSS into JS
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
],
|
|
67
|
+
// Don't bundle browser globals
|
|
68
|
+
external: [],
|
|
69
|
+
// Add CLI's node_modules to resolve path so Svelte runtime can be found
|
|
70
|
+
nodePaths: [cliNodeModules],
|
|
71
|
+
// Log level
|
|
72
|
+
logLevel: 'warning'
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
success: true,
|
|
77
|
+
outputPath,
|
|
78
|
+
size: (await fs.stat(outputPath)).size,
|
|
79
|
+
warnings: result.warnings
|
|
80
|
+
};
|
|
81
|
+
} catch (error) {
|
|
82
|
+
return {
|
|
83
|
+
success: false,
|
|
84
|
+
error: error.message,
|
|
85
|
+
errors: error.errors
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Bundle all islands in a component directory
|
|
92
|
+
*/
|
|
93
|
+
export async function bundleComponentIslands(componentDir, outputDir) {
|
|
94
|
+
const islandsDir = path.join(componentDir, 'islands');
|
|
95
|
+
|
|
96
|
+
// Check if islands directory exists
|
|
97
|
+
try {
|
|
98
|
+
await fs.access(islandsDir);
|
|
99
|
+
} catch {
|
|
100
|
+
// No islands directory
|
|
101
|
+
return { islands: [], success: true };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Find all .js files in islands directory
|
|
105
|
+
const files = await fs.readdir(islandsDir);
|
|
106
|
+
const islandFiles = files.filter((f) => f.endsWith('.js'));
|
|
107
|
+
|
|
108
|
+
if (islandFiles.length === 0) {
|
|
109
|
+
return { islands: [], success: true };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Create output directory
|
|
113
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
114
|
+
|
|
115
|
+
const results = [];
|
|
116
|
+
|
|
117
|
+
for (const islandFile of islandFiles) {
|
|
118
|
+
const inputPath = path.join(islandsDir, islandFile);
|
|
119
|
+
const outputPath = path.join(outputDir, islandFile);
|
|
120
|
+
|
|
121
|
+
console.log(pc.dim(` Bundling ${islandFile}...`));
|
|
122
|
+
|
|
123
|
+
const result = await bundleIsland(inputPath, outputPath);
|
|
124
|
+
|
|
125
|
+
if (result.success) {
|
|
126
|
+
const sizeKb = (result.size / 1024).toFixed(2);
|
|
127
|
+
console.log(pc.green(` ✓ ${islandFile} → ${sizeKb}kb`));
|
|
128
|
+
} else {
|
|
129
|
+
console.log(pc.red(` ✗ ${islandFile} failed:`));
|
|
130
|
+
console.log(pc.red(` ${result.error}`));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
results.push({
|
|
134
|
+
file: islandFile,
|
|
135
|
+
...result
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const allSuccess = results.every((r) => r.success);
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
islands: results,
|
|
143
|
+
success: allSuccess
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get total bundle size for all islands
|
|
149
|
+
*/
|
|
150
|
+
export function getTotalBundleSize(bundleResults) {
|
|
151
|
+
return bundleResults.islands.reduce((total, island) => {
|
|
152
|
+
return total + (island.size || 0);
|
|
153
|
+
}, 0);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Format bundle size in human-readable format
|
|
158
|
+
*/
|
|
159
|
+
export function formatSize(bytes) {
|
|
160
|
+
if (bytes < 1024) return `${bytes}B`;
|
|
161
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)}KB`;
|
|
162
|
+
return `${(bytes / (1024 * 1024)).toFixed(2)}MB`;
|
|
163
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { pathToFileURL } from 'url';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Load Webmate config from current project
|
|
7
|
+
*/
|
|
8
|
+
export async function loadConfig() {
|
|
9
|
+
const configPath = join(process.cwd(), 'wm.config.js');
|
|
10
|
+
|
|
11
|
+
// If no config file exists, return defaults
|
|
12
|
+
if (!existsSync(configPath)) {
|
|
13
|
+
return getDefaultConfig();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// Dynamic import with file URL
|
|
18
|
+
const configUrl = pathToFileURL(configPath).href;
|
|
19
|
+
const module = await import(configUrl);
|
|
20
|
+
const config = module.default || module;
|
|
21
|
+
|
|
22
|
+
// Merge with defaults
|
|
23
|
+
return {
|
|
24
|
+
...getDefaultConfig(),
|
|
25
|
+
...config
|
|
26
|
+
};
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.warn(`Warning: Could not load config from ${configPath}`);
|
|
29
|
+
console.warn(error.message);
|
|
30
|
+
return getDefaultConfig();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Get default configuration
|
|
36
|
+
*/
|
|
37
|
+
function getDefaultConfig() {
|
|
38
|
+
return {
|
|
39
|
+
version: '0.1.0', // Default version if not specified
|
|
40
|
+
components: {
|
|
41
|
+
path: './components',
|
|
42
|
+
styles: [],
|
|
43
|
+
fonts: [],
|
|
44
|
+
islands: {
|
|
45
|
+
path: './islands',
|
|
46
|
+
framework: 'lit'
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
preview: {
|
|
50
|
+
port: 5173,
|
|
51
|
+
theme: 'light',
|
|
52
|
+
viewport: {
|
|
53
|
+
width: 1440,
|
|
54
|
+
height: 900
|
|
55
|
+
},
|
|
56
|
+
backgrounds: ['#ffffff', '#f5f5f5', '#000000']
|
|
57
|
+
},
|
|
58
|
+
output: {
|
|
59
|
+
dir: './dist',
|
|
60
|
+
format: 'esm',
|
|
61
|
+
minify: false
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get path to config file
|
|
68
|
+
* @returns {string} Path to wm.config.js
|
|
69
|
+
*/
|
|
70
|
+
export function getConfigPath() {
|
|
71
|
+
return join(process.cwd(), 'wm.config.js');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Update version in config file
|
|
76
|
+
* @param {string} newVersion - New version string
|
|
77
|
+
*/
|
|
78
|
+
export function updateConfigVersion(newVersion) {
|
|
79
|
+
const configPath = getConfigPath();
|
|
80
|
+
|
|
81
|
+
if (!existsSync(configPath)) {
|
|
82
|
+
throw new Error('No wm.config.js found in current directory.');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let content = readFileSync(configPath, 'utf8');
|
|
86
|
+
|
|
87
|
+
// Check if version field exists
|
|
88
|
+
if (content.includes('version:')) {
|
|
89
|
+
// Update existing version
|
|
90
|
+
content = content.replace(
|
|
91
|
+
/version:\s*['"][\d.]+['"]/,
|
|
92
|
+
`version: '${newVersion}'`
|
|
93
|
+
);
|
|
94
|
+
} else {
|
|
95
|
+
// Add version field after export default {
|
|
96
|
+
content = content.replace(
|
|
97
|
+
/export default \{/,
|
|
98
|
+
`export default {\n\t// Component version (semantic versioning)\n\tversion: '${newVersion}',\n`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
writeFileSync(configPath, content, 'utf8');
|
|
103
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic Versioning Utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Parse a semantic version string
|
|
7
|
+
* @param {string} version - Version string (e.g., "1.2.3")
|
|
8
|
+
* @returns {{major: number, minor: number, patch: number}}
|
|
9
|
+
*/
|
|
10
|
+
export function parseVersion(version) {
|
|
11
|
+
const match = version.match(/^(\d+)\.(\d+)\.(\d+)$/);
|
|
12
|
+
|
|
13
|
+
if (!match) {
|
|
14
|
+
throw new Error(`Invalid version format: ${version}. Expected format: x.y.z`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
major: parseInt(match[1], 10),
|
|
19
|
+
minor: parseInt(match[2], 10),
|
|
20
|
+
patch: parseInt(match[3], 10)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Convert version object to string
|
|
26
|
+
* @param {{major: number, minor: number, patch: number}} version
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
export function versionToString(version) {
|
|
30
|
+
return `${version.major}.${version.minor}.${version.patch}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Increment patch version (1.2.3 → 1.2.4)
|
|
35
|
+
* @param {string} version - Current version
|
|
36
|
+
* @returns {string} - New version
|
|
37
|
+
*/
|
|
38
|
+
export function incrementPatch(version) {
|
|
39
|
+
const parsed = parseVersion(version);
|
|
40
|
+
parsed.patch += 1;
|
|
41
|
+
return versionToString(parsed);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Increment minor version (1.2.3 → 1.3.0)
|
|
46
|
+
* @param {string} version - Current version
|
|
47
|
+
* @returns {string} - New version
|
|
48
|
+
*/
|
|
49
|
+
export function incrementMinor(version) {
|
|
50
|
+
const parsed = parseVersion(version);
|
|
51
|
+
parsed.minor += 1;
|
|
52
|
+
parsed.patch = 0;
|
|
53
|
+
return versionToString(parsed);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Increment major version (1.2.3 → 2.0.0)
|
|
58
|
+
* @param {string} version - Current version
|
|
59
|
+
* @returns {string} - New version
|
|
60
|
+
*/
|
|
61
|
+
export function incrementMajor(version) {
|
|
62
|
+
const parsed = parseVersion(version);
|
|
63
|
+
parsed.major += 1;
|
|
64
|
+
parsed.minor = 0;
|
|
65
|
+
parsed.patch = 0;
|
|
66
|
+
return versionToString(parsed);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Validate version format
|
|
71
|
+
* @param {string} version - Version to validate
|
|
72
|
+
* @returns {boolean}
|
|
73
|
+
*/
|
|
74
|
+
export function isValidVersion(version) {
|
|
75
|
+
return /^\d+\.\d+\.\d+$/.test(version);
|
|
76
|
+
}
|