@pulse-editor/cli 0.1.1-beta.9 → 0.1.3
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/dist/app.js +4 -1
- package/dist/components/commands/build.js +18 -33
- package/dist/components/commands/code.d.ts +5 -0
- package/dist/components/commands/code.js +342 -0
- package/dist/components/commands/create.js +38 -12
- package/dist/components/commands/dev.js +35 -8
- package/dist/components/commands/login.d.ts +2 -2
- package/dist/components/commands/login.js +110 -26
- package/dist/components/commands/preview.js +50 -11
- package/dist/components/commands/publish.js +23 -37
- package/dist/components/commands/{start copy.d.ts → skill.d.ts} +1 -1
- package/dist/components/commands/skill.js +230 -0
- package/dist/components/commands/{preview copy.d.ts → upgrade.d.ts} +1 -1
- package/dist/components/commands/upgrade.js +53 -0
- package/dist/lib/backend/publish-app.d.ts +1 -0
- package/dist/lib/backend/publish-app.js +26 -0
- package/dist/lib/backend-url.d.ts +1 -0
- package/dist/lib/backend-url.js +3 -0
- package/dist/lib/cli-flags.d.ts +22 -0
- package/dist/lib/cli-flags.js +22 -0
- package/dist/lib/manual.js +40 -0
- package/dist/lib/server/express.js +81 -41
- package/dist/lib/server/preview/backend/load-remote.cjs +28 -18
- package/dist/lib/server/utils.js +3 -3
- package/dist/lib/token.js +2 -3
- package/dist/lib/webpack/compile.d.ts +2 -0
- package/dist/lib/webpack/compile.js +30 -0
- package/dist/lib/webpack/configs/mf-client.d.ts +3 -0
- package/dist/lib/webpack/configs/mf-client.js +184 -0
- package/dist/lib/webpack/configs/mf-server.d.ts +2 -0
- package/dist/lib/webpack/configs/mf-server.js +463 -0
- package/dist/lib/webpack/configs/preview.d.ts +3 -0
- package/dist/lib/webpack/configs/preview.js +117 -0
- package/dist/lib/webpack/configs/utils.d.ts +10 -0
- package/dist/lib/webpack/configs/utils.js +172 -0
- package/dist/lib/webpack/dist/pregistered-actions.d.ts +2 -0
- package/dist/lib/webpack/dist/pulse.config.d.ts +7 -0
- package/dist/lib/webpack/dist/src/lib/agents/code-modifier-agent.d.ts +2 -0
- package/dist/lib/webpack/dist/src/lib/agents/vibe-coding-agent.d.ts +3 -0
- package/dist/lib/webpack/dist/src/lib/mcp/utils.d.ts +3 -0
- package/dist/lib/webpack/dist/src/lib/streaming/message-stream-controller.d.ts +10 -0
- package/dist/lib/webpack/dist/src/lib/types.d.ts +58 -0
- package/dist/lib/webpack/dist/src/server-function/generate-code/v1/generate.d.ts +5 -0
- package/dist/lib/webpack/dist/src/server-function/generate-code/v2/generate.d.ts +1 -0
- package/dist/lib/webpack/tsconfig.server.json +19 -0
- package/dist/lib/webpack/webpack-config.d.ts +1 -0
- package/dist/lib/webpack/webpack-config.js +24 -0
- package/dist/lib/webpack/webpack.config.d.ts +2 -0
- package/dist/lib/webpack/webpack.config.js +527 -0
- package/package.json +31 -20
- package/readme.md +7 -1
- package/dist/components/commands/preview copy.js +0 -14
- package/dist/components/commands/start copy.js +0 -14
- package/dist/lib/deps.d.ts +0 -1
- package/dist/lib/deps.js +0 -5
- package/dist/lib/node_module_bin.d.ts +0 -1
- package/dist/lib/node_module_bin.js +0 -7
- package/dist/lib/server/preview/backend/index.d.ts +0 -1
- package/dist/lib/server/preview/backend/index.js +0 -23
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { ModuleFederationPlugin } from '@module-federation/enhanced/webpack';
|
|
3
|
+
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
|
4
|
+
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
|
5
|
+
import { networkInterfaces } from 'os';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { globSync } from 'glob';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import CopyWebpackPlugin from 'copy-webpack-plugin';
|
|
10
|
+
import ts from 'typescript';
|
|
11
|
+
import { pathToFileURL } from 'url';
|
|
12
|
+
import mfNode from '@module-federation/node';
|
|
13
|
+
const { NodeFederationPlugin } = mfNode;
|
|
14
|
+
import wp from 'webpack';
|
|
15
|
+
const { webpack } = wp;
|
|
16
|
+
export async function createWebpackConfig(isPreview, buildTarget, mode) {
|
|
17
|
+
const projectDirName = process.cwd();
|
|
18
|
+
async function loadPulseConfig() {
|
|
19
|
+
// compile to js file and import
|
|
20
|
+
const program = ts.createProgram({
|
|
21
|
+
rootNames: [path.join(projectDirName, 'pulse.config.ts')],
|
|
22
|
+
options: {
|
|
23
|
+
module: ts.ModuleKind.ESNext,
|
|
24
|
+
target: ts.ScriptTarget.ES2020,
|
|
25
|
+
outDir: path.join(projectDirName, 'node_modules/.pulse/config'),
|
|
26
|
+
esModuleInterop: true,
|
|
27
|
+
skipLibCheck: true,
|
|
28
|
+
forceConsistentCasingInFileNames: true,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
program.emit();
|
|
32
|
+
// Fix imports in the generated js file for all files in node_modules/.pulse/config
|
|
33
|
+
globSync('node_modules/.pulse/config/**/*.js', {
|
|
34
|
+
cwd: projectDirName,
|
|
35
|
+
absolute: true,
|
|
36
|
+
}).forEach(jsFile => {
|
|
37
|
+
let content = fs.readFileSync(jsFile, 'utf-8');
|
|
38
|
+
content = content.replace(/(from\s+["']\.\/[^\s"']+)(["'])/g, (match, p1, p2) => {
|
|
39
|
+
// No change if the import already has any extension
|
|
40
|
+
if (p1.match(/\.(js|cjs|mjs|ts|tsx|json)$/)) {
|
|
41
|
+
return match; // No change needed
|
|
42
|
+
}
|
|
43
|
+
return `${p1}.js${p2}`;
|
|
44
|
+
});
|
|
45
|
+
fs.writeFileSync(jsFile, content);
|
|
46
|
+
});
|
|
47
|
+
// Copy package.json if exists
|
|
48
|
+
const pkgPath = path.join(projectDirName, 'package.json');
|
|
49
|
+
if (fs.existsSync(pkgPath)) {
|
|
50
|
+
const destPath = path.join(projectDirName, 'node_modules/.pulse/config/package.json');
|
|
51
|
+
fs.copyFileSync(pkgPath, destPath);
|
|
52
|
+
}
|
|
53
|
+
const compiledConfig = path.join(projectDirName, 'node_modules/.pulse/config/pulse.config.js');
|
|
54
|
+
const mod = await import(pathToFileURL(compiledConfig).href);
|
|
55
|
+
// delete the compiled config after importing
|
|
56
|
+
fs.rmSync(path.join(projectDirName, 'node_modules/.pulse/config'), {
|
|
57
|
+
recursive: true,
|
|
58
|
+
force: true,
|
|
59
|
+
});
|
|
60
|
+
return mod.default;
|
|
61
|
+
}
|
|
62
|
+
const pulseConfig = await loadPulseConfig();
|
|
63
|
+
function getLocalNetworkIP() {
|
|
64
|
+
const interfaces = networkInterfaces();
|
|
65
|
+
for (const iface of Object.values(interfaces)) {
|
|
66
|
+
if (!iface)
|
|
67
|
+
continue;
|
|
68
|
+
for (const config of iface) {
|
|
69
|
+
if (config.family === 'IPv4' && !config.internal) {
|
|
70
|
+
return config.address; // Returns the first non-internal IPv4 address
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return 'localhost'; // Fallback
|
|
75
|
+
}
|
|
76
|
+
const origin = getLocalNetworkIP();
|
|
77
|
+
const previewStartupMessage = `
|
|
78
|
+
🎉 Your Pulse extension preview \x1b[1m${pulseConfig.displayName}\x1b[0m is LIVE!
|
|
79
|
+
|
|
80
|
+
⚡️ Local: http://localhost:3030
|
|
81
|
+
⚡️ Network: http://${origin}:3030
|
|
82
|
+
|
|
83
|
+
✨ Try it out in your browser and let the magic happen! 🚀
|
|
84
|
+
`;
|
|
85
|
+
const devStartupMessage = `
|
|
86
|
+
🎉 Your Pulse extension \x1b[1m${pulseConfig.displayName}\x1b[0m is LIVE!
|
|
87
|
+
|
|
88
|
+
⚡️ Local: http://localhost:3030/${pulseConfig.id}/${pulseConfig.version}/
|
|
89
|
+
⚡️ Network: http://${origin}:3030/${pulseConfig.id}/${pulseConfig.version}/
|
|
90
|
+
|
|
91
|
+
✨ Try it out in the Pulse Editor and let the magic happen! 🚀
|
|
92
|
+
`;
|
|
93
|
+
// #region Node Federation Plugin for Server Functions
|
|
94
|
+
function makeNodeFederationPlugin() {
|
|
95
|
+
function discoverServerFunctions() {
|
|
96
|
+
// Get all .ts files under src/server-function and read use default exports as entry points
|
|
97
|
+
const files = globSync('./src/server-function/**/*.ts');
|
|
98
|
+
const entryPoints = files
|
|
99
|
+
.map(file => file.replaceAll('\\', '/'))
|
|
100
|
+
.map(file => {
|
|
101
|
+
return {
|
|
102
|
+
['./' +
|
|
103
|
+
file.replace('src/server-function/', '').replace(/\.ts$/, '')]: './' + file,
|
|
104
|
+
};
|
|
105
|
+
})
|
|
106
|
+
.reduce((acc, curr) => {
|
|
107
|
+
return { ...acc, ...curr };
|
|
108
|
+
}, {});
|
|
109
|
+
return entryPoints;
|
|
110
|
+
}
|
|
111
|
+
const funcs = discoverServerFunctions();
|
|
112
|
+
console.log(`Discovered server functions:
|
|
113
|
+
${Object.entries(funcs)
|
|
114
|
+
.map(([name, file]) => {
|
|
115
|
+
return ` - ${name.slice(2)} (from ${file})`;
|
|
116
|
+
})
|
|
117
|
+
.join('\n')}
|
|
118
|
+
`);
|
|
119
|
+
return new NodeFederationPlugin({
|
|
120
|
+
name: pulseConfig.id + '_server',
|
|
121
|
+
remoteType: 'script',
|
|
122
|
+
useRuntimePlugin: true,
|
|
123
|
+
library: { type: 'commonjs-module' },
|
|
124
|
+
filename: 'remoteEntry.js',
|
|
125
|
+
exposes: {
|
|
126
|
+
...funcs,
|
|
127
|
+
},
|
|
128
|
+
}, {});
|
|
129
|
+
}
|
|
130
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
131
|
+
function compileServerFunctions(compiler) {
|
|
132
|
+
// Remove existing entry points
|
|
133
|
+
try {
|
|
134
|
+
fs.rmSync('dist/server', { recursive: true, force: true });
|
|
135
|
+
}
|
|
136
|
+
catch (e) {
|
|
137
|
+
console.error('Error removing dist/server:', e);
|
|
138
|
+
console.log('Continuing...');
|
|
139
|
+
}
|
|
140
|
+
// Generate tsconfig for server functions
|
|
141
|
+
function generateTempTsConfig() {
|
|
142
|
+
const tempTsConfigPath = path.join(process.cwd(), 'node_modules/.pulse/tsconfig.server.json');
|
|
143
|
+
const tsConfig = {
|
|
144
|
+
compilerOptions: {
|
|
145
|
+
target: 'ES2020',
|
|
146
|
+
module: 'esnext',
|
|
147
|
+
moduleResolution: 'bundler',
|
|
148
|
+
strict: true,
|
|
149
|
+
declaration: true,
|
|
150
|
+
outDir: path.join(process.cwd(), 'dist'),
|
|
151
|
+
},
|
|
152
|
+
include: [
|
|
153
|
+
path.join(process.cwd(), 'src/server-function/**/*'),
|
|
154
|
+
path.join(process.cwd(), 'pulse.config.ts'),
|
|
155
|
+
path.join(process.cwd(), 'global.d.ts'),
|
|
156
|
+
],
|
|
157
|
+
exclude: [
|
|
158
|
+
path.join(process.cwd(), 'node_modules'),
|
|
159
|
+
path.join(process.cwd(), 'dist'),
|
|
160
|
+
],
|
|
161
|
+
};
|
|
162
|
+
fs.writeFileSync(tempTsConfigPath, JSON.stringify(tsConfig, null, 2));
|
|
163
|
+
}
|
|
164
|
+
generateTempTsConfig();
|
|
165
|
+
// Run a new webpack compilation to pick up new server functions
|
|
166
|
+
const options = {
|
|
167
|
+
...compiler.options,
|
|
168
|
+
watch: false,
|
|
169
|
+
plugins: [
|
|
170
|
+
// Add a new NodeFederationPlugin with updated entry points
|
|
171
|
+
makeNodeFederationPlugin(),
|
|
172
|
+
],
|
|
173
|
+
};
|
|
174
|
+
const newCompiler = webpack(options);
|
|
175
|
+
// Run the new compiler
|
|
176
|
+
newCompiler?.run((err, stats) => {
|
|
177
|
+
if (err) {
|
|
178
|
+
console.error(`[Server] ❌ Error during recompilation:`, err);
|
|
179
|
+
}
|
|
180
|
+
else if (stats?.hasErrors()) {
|
|
181
|
+
console.error(`[Server] ❌ Compilation errors:`, stats.toJson().errors);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
console.log(`[Server] ✅ Compiled server functions successfully.`);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
// #endregion
|
|
189
|
+
// #region Source file parser for Pulse Config plugin
|
|
190
|
+
class PulseConfigPlugin {
|
|
191
|
+
requireFS = false;
|
|
192
|
+
apply(compiler) {
|
|
193
|
+
compiler.hooks.beforeCompile.tap('PulseConfigPlugin', () => {
|
|
194
|
+
this.requireFS = false;
|
|
195
|
+
globSync(['src/**/*.tsx', 'src/**/*.ts']).forEach(file => {
|
|
196
|
+
const source = fs.readFileSync(file, 'utf8');
|
|
197
|
+
this.scanSource(source);
|
|
198
|
+
});
|
|
199
|
+
// Persist result
|
|
200
|
+
pulseConfig.requireWorkspace = this.requireFS;
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
isWorkspaceHook(node) {
|
|
204
|
+
return (ts.isCallExpression(node) &&
|
|
205
|
+
ts.isIdentifier(node.expression) &&
|
|
206
|
+
[
|
|
207
|
+
'useFileSystem',
|
|
208
|
+
'useFile',
|
|
209
|
+
'useReceiveFile',
|
|
210
|
+
'useTerminal',
|
|
211
|
+
'useWorkspaceInfo',
|
|
212
|
+
].includes(node.expression.text));
|
|
213
|
+
}
|
|
214
|
+
scanSource(sourceText) {
|
|
215
|
+
const sourceFile = ts.createSourceFile('temp.tsx', sourceText, ts.ScriptTarget.Latest, true);
|
|
216
|
+
const visit = (node) => {
|
|
217
|
+
// Detect: useFileSystem(...)
|
|
218
|
+
if (this.isWorkspaceHook(node)) {
|
|
219
|
+
this.requireFS = true;
|
|
220
|
+
}
|
|
221
|
+
ts.forEachChild(node, visit);
|
|
222
|
+
};
|
|
223
|
+
visit(sourceFile);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// #endregion
|
|
227
|
+
// #region Webpack Configs
|
|
228
|
+
const previewClientConfig = {
|
|
229
|
+
mode: mode,
|
|
230
|
+
entry: {
|
|
231
|
+
main: './node_modules/.pulse/server/preview/frontend/index.js',
|
|
232
|
+
},
|
|
233
|
+
output: {
|
|
234
|
+
path: path.resolve(projectDirName, 'dist/client'),
|
|
235
|
+
},
|
|
236
|
+
resolve: {
|
|
237
|
+
extensions: ['.ts', '.tsx', '.js'],
|
|
238
|
+
},
|
|
239
|
+
plugins: [
|
|
240
|
+
new PulseConfigPlugin(),
|
|
241
|
+
new HtmlWebpackPlugin({
|
|
242
|
+
template: './node_modules/.pulse/server/preview/frontend/index.html',
|
|
243
|
+
}),
|
|
244
|
+
new MiniCssExtractPlugin({
|
|
245
|
+
filename: 'globals.css',
|
|
246
|
+
}),
|
|
247
|
+
new CopyWebpackPlugin({
|
|
248
|
+
patterns: [{ from: 'src/assets', to: 'assets' }],
|
|
249
|
+
}),
|
|
250
|
+
{
|
|
251
|
+
apply: compiler => {
|
|
252
|
+
let isFirstRun = true;
|
|
253
|
+
// Before build starts
|
|
254
|
+
compiler.hooks.watchRun.tap('ReloadMessagePlugin', () => {
|
|
255
|
+
if (!isFirstRun) {
|
|
256
|
+
console.log('[client-preview] 🔄 Reloading app...');
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
console.log('[client-preview] 🔄 Building app...');
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
// After build finishes
|
|
263
|
+
compiler.hooks.done.tap('ReloadMessagePlugin', () => {
|
|
264
|
+
if (isFirstRun) {
|
|
265
|
+
console.log('[client-preview] ✅ Successfully built preview.');
|
|
266
|
+
console.log(previewStartupMessage);
|
|
267
|
+
isFirstRun = false;
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
console.log('[client-preview] ✅ Reload finished');
|
|
271
|
+
}
|
|
272
|
+
// Write pulse config to dist
|
|
273
|
+
fs.writeFileSync(path.resolve(projectDirName, 'dist/client/pulse.config.json'), JSON.stringify(pulseConfig, null, 2));
|
|
274
|
+
fs.writeFileSync(path.resolve(projectDirName, 'dist/server/pulse.config.json'), JSON.stringify(pulseConfig, null, 2));
|
|
275
|
+
});
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
watchOptions: {
|
|
280
|
+
ignored: /src\/server-function/,
|
|
281
|
+
},
|
|
282
|
+
module: {
|
|
283
|
+
rules: [
|
|
284
|
+
{
|
|
285
|
+
test: /\.tsx?$/,
|
|
286
|
+
use: 'ts-loader',
|
|
287
|
+
exclude: [/node_modules/, /dist/],
|
|
288
|
+
},
|
|
289
|
+
{
|
|
290
|
+
test: /\.css$/i,
|
|
291
|
+
use: [
|
|
292
|
+
MiniCssExtractPlugin.loader,
|
|
293
|
+
'css-loader',
|
|
294
|
+
{
|
|
295
|
+
loader: 'postcss-loader',
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
},
|
|
301
|
+
stats: {
|
|
302
|
+
all: false,
|
|
303
|
+
errors: true,
|
|
304
|
+
warnings: true,
|
|
305
|
+
logging: 'warn',
|
|
306
|
+
colors: true,
|
|
307
|
+
},
|
|
308
|
+
infrastructureLogging: {
|
|
309
|
+
level: 'warn',
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
const mfClientConfig = {
|
|
313
|
+
mode: mode,
|
|
314
|
+
name: 'client',
|
|
315
|
+
entry: './src/main.tsx',
|
|
316
|
+
output: {
|
|
317
|
+
publicPath: 'auto',
|
|
318
|
+
path: path.resolve(projectDirName, 'dist/client'),
|
|
319
|
+
},
|
|
320
|
+
resolve: {
|
|
321
|
+
extensions: ['.ts', '.tsx', '.js'],
|
|
322
|
+
},
|
|
323
|
+
plugins: [
|
|
324
|
+
new PulseConfigPlugin(),
|
|
325
|
+
new MiniCssExtractPlugin({
|
|
326
|
+
filename: 'globals.css',
|
|
327
|
+
}),
|
|
328
|
+
// Copy assets to dist
|
|
329
|
+
new CopyWebpackPlugin({
|
|
330
|
+
patterns: [{ from: 'src/assets', to: 'assets' }],
|
|
331
|
+
}),
|
|
332
|
+
new ModuleFederationPlugin({
|
|
333
|
+
// Do not use hyphen character '-' in the name
|
|
334
|
+
name: pulseConfig.id,
|
|
335
|
+
filename: 'remoteEntry.js',
|
|
336
|
+
exposes: {
|
|
337
|
+
'./main': './src/main.tsx',
|
|
338
|
+
},
|
|
339
|
+
shared: {
|
|
340
|
+
react: {
|
|
341
|
+
requiredVersion: '19.2.0',
|
|
342
|
+
import: 'react', // the "react" package will be used a provided and fallback module
|
|
343
|
+
shareKey: 'react', // under this name the shared module will be placed in the share scope
|
|
344
|
+
shareScope: 'default', // share scope with this name will be used
|
|
345
|
+
singleton: true, // only a single version of the shared module is allowed
|
|
346
|
+
},
|
|
347
|
+
'react-dom': {
|
|
348
|
+
requiredVersion: '19.2.0',
|
|
349
|
+
singleton: true, // only a single version of the shared module is allowed
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
}),
|
|
353
|
+
{
|
|
354
|
+
apply: compiler => {
|
|
355
|
+
if (compiler.options.mode === 'development') {
|
|
356
|
+
let isFirstRun = true;
|
|
357
|
+
// Before build starts
|
|
358
|
+
compiler.hooks.watchRun.tap('ReloadMessagePlugin', () => {
|
|
359
|
+
if (!isFirstRun) {
|
|
360
|
+
console.log('[client] 🔄 reloading app...');
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
console.log('[client] 🔄 building app...');
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
// Log file updates
|
|
367
|
+
compiler.hooks.invalid.tap('LogFileUpdates', (file, changeTime) => {
|
|
368
|
+
console.log(`[watch] change detected in: ${file} at ${new Date(changeTime || Date.now()).toLocaleTimeString()}`);
|
|
369
|
+
});
|
|
370
|
+
// After build finishes
|
|
371
|
+
compiler.hooks.done.tap('ReloadMessagePlugin', () => {
|
|
372
|
+
if (isFirstRun) {
|
|
373
|
+
console.log('[client] ✅ Successfully built client.');
|
|
374
|
+
console.log(devStartupMessage);
|
|
375
|
+
isFirstRun = false;
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
console.log('[client] ✅ Reload finished.');
|
|
379
|
+
}
|
|
380
|
+
// Write pulse config to dist
|
|
381
|
+
fs.writeFileSync(path.resolve(projectDirName, 'dist/client/pulse.config.json'), JSON.stringify(pulseConfig, null, 2));
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
// Print build success/failed message
|
|
386
|
+
compiler.hooks.done.tap('BuildMessagePlugin', stats => {
|
|
387
|
+
if (stats.hasErrors()) {
|
|
388
|
+
console.log(`[client] ❌ Failed to build client.`);
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
console.log(`[client] ✅ Successfully built client.`);
|
|
392
|
+
// Write pulse config to dist
|
|
393
|
+
fs.writeFileSync(path.resolve(projectDirName, 'dist/client/pulse.config.json'), JSON.stringify(pulseConfig, null, 2));
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
],
|
|
400
|
+
module: {
|
|
401
|
+
rules: [
|
|
402
|
+
{
|
|
403
|
+
test: /\.tsx?$/,
|
|
404
|
+
use: 'ts-loader',
|
|
405
|
+
exclude: [/node_modules/, /dist/],
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
test: /\.css$/i,
|
|
409
|
+
use: [
|
|
410
|
+
MiniCssExtractPlugin.loader,
|
|
411
|
+
'css-loader',
|
|
412
|
+
{
|
|
413
|
+
loader: 'postcss-loader',
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
exclude: [/dist/],
|
|
417
|
+
},
|
|
418
|
+
],
|
|
419
|
+
},
|
|
420
|
+
stats: {
|
|
421
|
+
all: false,
|
|
422
|
+
errors: true,
|
|
423
|
+
warnings: true,
|
|
424
|
+
logging: 'warn',
|
|
425
|
+
colors: true,
|
|
426
|
+
assets: false,
|
|
427
|
+
},
|
|
428
|
+
infrastructureLogging: {
|
|
429
|
+
level: 'warn',
|
|
430
|
+
},
|
|
431
|
+
};
|
|
432
|
+
const mfServerConfig = {
|
|
433
|
+
mode: mode,
|
|
434
|
+
name: 'server',
|
|
435
|
+
entry: {},
|
|
436
|
+
target: 'async-node',
|
|
437
|
+
output: {
|
|
438
|
+
publicPath: 'auto',
|
|
439
|
+
path: path.resolve(projectDirName, 'dist/server'),
|
|
440
|
+
},
|
|
441
|
+
resolve: {
|
|
442
|
+
extensions: ['.ts', '.js'],
|
|
443
|
+
},
|
|
444
|
+
plugins: [
|
|
445
|
+
{
|
|
446
|
+
apply: compiler => {
|
|
447
|
+
if (compiler.options.mode === 'development') {
|
|
448
|
+
let isFirstRun = true;
|
|
449
|
+
// Before build starts
|
|
450
|
+
compiler.hooks.watchRun.tap('ReloadMessagePlugin', () => {
|
|
451
|
+
if (!isFirstRun) {
|
|
452
|
+
console.log(`[Server] 🔄 Reloading app...`);
|
|
453
|
+
}
|
|
454
|
+
else {
|
|
455
|
+
console.log(`[Server] 🔄 Building app...`);
|
|
456
|
+
}
|
|
457
|
+
compileServerFunctions(compiler);
|
|
458
|
+
});
|
|
459
|
+
// After build finishes
|
|
460
|
+
compiler.hooks.done.tap('ReloadMessagePlugin', () => {
|
|
461
|
+
if (isFirstRun) {
|
|
462
|
+
console.log(`[Server] ✅ Successfully built server.`);
|
|
463
|
+
isFirstRun = false;
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
console.log(`[Server] ✅ Reload finished.`);
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
// Watch for changes in the server-function directory to trigger rebuilds
|
|
470
|
+
compiler.hooks.thisCompilation.tap('WatchServerFunctions', compilation => {
|
|
471
|
+
compilation.contextDependencies.add(path.resolve(projectDirName, 'src/server-function'));
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
// Print build success/failed message
|
|
476
|
+
compiler.hooks.done.tap('BuildMessagePlugin', stats => {
|
|
477
|
+
if (stats.hasErrors()) {
|
|
478
|
+
console.log(`[Server] ❌ Failed to build server.`);
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
compileServerFunctions(compiler);
|
|
482
|
+
console.log(`[Server] ✅ Successfully built server.`);
|
|
483
|
+
}
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
],
|
|
489
|
+
module: {
|
|
490
|
+
rules: [
|
|
491
|
+
{
|
|
492
|
+
test: /\.tsx?$/,
|
|
493
|
+
use: {
|
|
494
|
+
loader: 'ts-loader',
|
|
495
|
+
options: {
|
|
496
|
+
configFile: 'node_modules/.pulse/tsconfig.server.json',
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
exclude: [/node_modules/, /dist/],
|
|
500
|
+
},
|
|
501
|
+
],
|
|
502
|
+
},
|
|
503
|
+
stats: {
|
|
504
|
+
all: false,
|
|
505
|
+
errors: true,
|
|
506
|
+
warnings: true,
|
|
507
|
+
logging: 'warn',
|
|
508
|
+
colors: true,
|
|
509
|
+
},
|
|
510
|
+
infrastructureLogging: {
|
|
511
|
+
level: 'warn',
|
|
512
|
+
},
|
|
513
|
+
};
|
|
514
|
+
// #endregion
|
|
515
|
+
if (isPreview) {
|
|
516
|
+
return [previewClientConfig, mfServerConfig];
|
|
517
|
+
}
|
|
518
|
+
else if (buildTarget === 'server') {
|
|
519
|
+
return [mfServerConfig];
|
|
520
|
+
}
|
|
521
|
+
else if (buildTarget === 'client') {
|
|
522
|
+
return [mfClientConfig];
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
return [mfClientConfig, mfServerConfig];
|
|
526
|
+
}
|
|
527
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pulse-editor/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bin": {
|
|
6
6
|
"pulse": "dist/cli.js"
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "tsx build.ts",
|
|
14
|
-
"dev": "tsx watch --include \"./
|
|
14
|
+
"dev": "tsx watch --include \"./src/**/*\" build.ts",
|
|
15
15
|
"test": "prettier --check . && xo && ava",
|
|
16
16
|
"link": "npm link"
|
|
17
17
|
},
|
|
@@ -19,48 +19,60 @@
|
|
|
19
19
|
"dist"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
+
"@module-federation/enhanced": "2.0.1",
|
|
23
|
+
"@module-federation/node": "2.7.32",
|
|
24
|
+
"@module-federation/runtime": "2.0.1",
|
|
25
|
+
"@pulse-editor/shared-utils": "^0.1.1-beta.76",
|
|
22
26
|
"concurrently": "^9.2.1",
|
|
23
27
|
"connect-livereload": "^0.6.1",
|
|
24
|
-
"
|
|
28
|
+
"copy-webpack-plugin": "^13.0.1",
|
|
29
|
+
"cors": "^2.8.6",
|
|
25
30
|
"cross-env": "^10.1.0",
|
|
26
|
-
"dotenv": "^17.
|
|
31
|
+
"dotenv": "^17.3.1",
|
|
27
32
|
"execa": "^9.6.1",
|
|
28
33
|
"express": "^5.2.1",
|
|
29
|
-
"
|
|
34
|
+
"glob": "^13.0.6",
|
|
35
|
+
"html-webpack-plugin": "^5.6.6",
|
|
36
|
+
"ink": "^6.8.0",
|
|
30
37
|
"ink-select-input": "^6.2.0",
|
|
31
38
|
"ink-spinner": "^5.0.0",
|
|
32
39
|
"ink-text-input": "^6.0.0",
|
|
40
|
+
"jszip": "^3.10.1",
|
|
33
41
|
"livereload": "^0.10.3",
|
|
34
|
-
"meow": "^14.
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"tsx": "^4.21.0"
|
|
42
|
+
"meow": "^14.1.0",
|
|
43
|
+
"mini-css-extract-plugin": "^2.10.0",
|
|
44
|
+
"openid-client": "^6.8.2",
|
|
45
|
+
"rimraf": "^6.1.3",
|
|
46
|
+
"ts-morph": "^27.0.2",
|
|
47
|
+
"tsx": "^4.21.0",
|
|
48
|
+
"webpack": "^5.105.2",
|
|
49
|
+
"webpack-dev-server": "^5.2.3"
|
|
40
50
|
},
|
|
41
51
|
"devDependencies": {
|
|
42
|
-
"@module-federation/enhanced": "0.21.6",
|
|
43
|
-
"@module-federation/node": "2.7.25",
|
|
44
|
-
"@module-federation/runtime": "0.21.6",
|
|
45
52
|
"@sindresorhus/tsconfig": "^8.1.0",
|
|
46
53
|
"@types/connect-livereload": "^0.6.3",
|
|
47
54
|
"@types/cors": "^2.8.19",
|
|
48
55
|
"@types/express": "^5.0.6",
|
|
56
|
+
"@types/jszip": "^3.4.0",
|
|
49
57
|
"@types/livereload": "^0.9.5",
|
|
50
|
-
"@types/react": "^19.2.
|
|
58
|
+
"@types/react": "^19.2.14",
|
|
51
59
|
"@types/react-dom": "^19.2.3",
|
|
52
|
-
"@vdemedes/prettier-config": "^2.0.1",
|
|
53
60
|
"ava": "^6.4.1",
|
|
54
61
|
"chalk": "^5.6.2",
|
|
55
62
|
"eslint-config-xo-react": "^0.29.0",
|
|
56
63
|
"eslint-plugin-react": "^7.37.5",
|
|
57
64
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
58
65
|
"ink-testing-library": "^4.0.0",
|
|
59
|
-
"
|
|
66
|
+
"react": "19.2.4",
|
|
67
|
+
"react-dom": "19.2.4",
|
|
60
68
|
"ts-node": "^10.9.2",
|
|
61
69
|
"typescript": "^5.9.3",
|
|
62
70
|
"xo": "^1.2.3"
|
|
63
71
|
},
|
|
72
|
+
"peerDependencies": {
|
|
73
|
+
"react": "19.2.4",
|
|
74
|
+
"react-dom": "19.2.4"
|
|
75
|
+
},
|
|
64
76
|
"ava": {
|
|
65
77
|
"extensions": {
|
|
66
78
|
"ts": "module",
|
|
@@ -76,6 +88,5 @@
|
|
|
76
88
|
"rules": {
|
|
77
89
|
"react/prop-types": "off"
|
|
78
90
|
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
}
|
|
91
|
+
}
|
|
92
|
+
}
|
package/readme.md
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
# Pulse CLI
|
|
2
|
+
|
|
2
3
|
## Install
|
|
4
|
+
|
|
3
5
|
```bash
|
|
4
6
|
$ npm install --global @pulse-editor/cli
|
|
5
7
|
```
|
|
6
8
|
|
|
7
9
|
## Link local development version
|
|
10
|
+
|
|
8
11
|
```bash
|
|
9
12
|
npm run link
|
|
10
13
|
```
|
|
@@ -48,6 +51,8 @@ npm run link
|
|
|
48
51
|
--visibility, -v [visibility]
|
|
49
52
|
The visibility of the new project. Options are private,
|
|
50
53
|
public, and unlisted.
|
|
54
|
+
--path, -p [path]
|
|
55
|
+
The path where to create the new project. Defaults to the name of the project in the current working directory.
|
|
51
56
|
|
|
52
57
|
preview Build the Pulse App in development mode and
|
|
53
58
|
start a preview server accessible via browser
|
|
@@ -75,6 +80,7 @@ npm run link
|
|
|
75
80
|
```
|
|
76
81
|
|
|
77
82
|
## Development
|
|
83
|
+
|
|
78
84
|
```
|
|
79
85
|
npm run dev
|
|
80
|
-
```
|
|
86
|
+
```
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Text } from 'ink';
|
|
3
|
-
import { useEffect } from 'react';
|
|
4
|
-
import { execa } from 'execa';
|
|
5
|
-
export default function Preview({ cli }) {
|
|
6
|
-
useEffect(() => {
|
|
7
|
-
// Start dev server
|
|
8
|
-
execa('npm run preview', {
|
|
9
|
-
stdio: 'inherit',
|
|
10
|
-
shell: true,
|
|
11
|
-
});
|
|
12
|
-
}, []);
|
|
13
|
-
return (_jsx(_Fragment, { children: _jsx(Text, { children: "Starting preview server..." }) }));
|
|
14
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Text } from 'ink';
|
|
3
|
-
import { useEffect } from 'react';
|
|
4
|
-
import { execa } from 'execa';
|
|
5
|
-
export default function Start({ cli }) {
|
|
6
|
-
useEffect(() => {
|
|
7
|
-
// Start dev server
|
|
8
|
-
execa('npm run start', {
|
|
9
|
-
stdio: 'inherit',
|
|
10
|
-
shell: true,
|
|
11
|
-
});
|
|
12
|
-
}, []);
|
|
13
|
-
return (_jsx(_Fragment, { children: _jsx(Text, { children: "Starting prod server..." }) }));
|
|
14
|
-
}
|