@hubspot/cli 8.0.10-experimental.0 → 8.0.10-experimental.1
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.
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import cliProgress from 'cli-progress';
|
|
4
3
|
import { commands } from '../../../lang/en.js';
|
|
5
4
|
import { getCwd } from '@hubspot/local-dev-lib/path';
|
|
6
|
-
import { FILE_UPLOAD_RESULT_TYPES } from '@hubspot/local-dev-lib/constants/files';
|
|
7
5
|
import { getThemeJSONPath } from '@hubspot/local-dev-lib/cms/themes';
|
|
8
|
-
|
|
9
|
-
import {
|
|
6
|
+
// Use subprocess approach to avoid React version conflicts
|
|
7
|
+
// import { createDevServer } from '@hubspot/cms-dev-server';
|
|
8
|
+
import { spawnDevServer } from '../../../lib/cms/devServerProcess.js';
|
|
10
9
|
import { trackCommandUsage } from '../../../lib/usageTracking.js';
|
|
11
10
|
import { previewPrompt, previewProjectPrompt, } from '../../../lib/prompts/previewPrompt.js';
|
|
12
11
|
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
13
|
-
import { ApiErrorContext, logError } from '../../../lib/errorHandlers/index.js';
|
|
14
12
|
import { getProjectConfig } from '../../../lib/projects/config.js';
|
|
15
13
|
import { findProjectComponents } from '../../../lib/projects/structure.js';
|
|
16
14
|
import { ComponentTypes } from '../../../types/Projects.js';
|
|
@@ -73,67 +71,16 @@ async function determineSrcAndDest(args) {
|
|
|
73
71
|
async function handler(args) {
|
|
74
72
|
const { derivedAccountId, noSsl, resetSession, port, generateFieldsTypes } = args;
|
|
75
73
|
const { absoluteSrc, dest } = await determineSrcAndDest(args);
|
|
76
|
-
const filePaths = await getUploadableFileList(absoluteSrc, false);
|
|
77
|
-
function startProgressBar(numFiles) {
|
|
78
|
-
const initialUploadProgressBar = new cliProgress.SingleBar({
|
|
79
|
-
gracefulExit: true,
|
|
80
|
-
format: '[{bar}] {percentage}% | {value}/{total} | {label}',
|
|
81
|
-
hideCursor: true,
|
|
82
|
-
}, cliProgress.Presets.rect);
|
|
83
|
-
initialUploadProgressBar.start(numFiles, 0, {
|
|
84
|
-
label: commands.cms.subcommands.theme.subcommands.preview
|
|
85
|
-
.initialUploadProgressBar.start,
|
|
86
|
-
});
|
|
87
|
-
let uploadsHaveStarted = false;
|
|
88
|
-
const uploadOptions = {
|
|
89
|
-
onAttemptCallback: () => {
|
|
90
|
-
/* Intentionally blank */
|
|
91
|
-
},
|
|
92
|
-
onSuccessCallback: () => {
|
|
93
|
-
initialUploadProgressBar.increment();
|
|
94
|
-
if (!uploadsHaveStarted) {
|
|
95
|
-
uploadsHaveStarted = true;
|
|
96
|
-
initialUploadProgressBar.update(0, {
|
|
97
|
-
label: commands.cms.subcommands.theme.subcommands.preview
|
|
98
|
-
.initialUploadProgressBar.uploading,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
},
|
|
102
|
-
onFirstErrorCallback: () => {
|
|
103
|
-
/* Intentionally blank */
|
|
104
|
-
},
|
|
105
|
-
onRetryCallback: () => {
|
|
106
|
-
/* Intentionally blank */
|
|
107
|
-
},
|
|
108
|
-
onFinalErrorCallback: () => initialUploadProgressBar.increment(),
|
|
109
|
-
onFinishCallback: (results) => {
|
|
110
|
-
initialUploadProgressBar.update(numFiles, {
|
|
111
|
-
label: commands.cms.subcommands.theme.subcommands.preview
|
|
112
|
-
.initialUploadProgressBar.finish,
|
|
113
|
-
});
|
|
114
|
-
initialUploadProgressBar.stop();
|
|
115
|
-
results.forEach(result => {
|
|
116
|
-
if (result.resultType == FILE_UPLOAD_RESULT_TYPES.FAILURE) {
|
|
117
|
-
uiLogger.error(commands.cms.subcommands.theme.subcommands.preview.errors.uploadFailed(result.file, dest));
|
|
118
|
-
logError(result.error, new ApiErrorContext({
|
|
119
|
-
accountId: derivedAccountId,
|
|
120
|
-
request: dest,
|
|
121
|
-
payload: result.file,
|
|
122
|
-
}));
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
},
|
|
126
|
-
};
|
|
127
|
-
return uploadOptions;
|
|
128
|
-
}
|
|
129
74
|
trackCommandUsage('preview', {}, derivedAccountId);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
75
|
+
// Spawn dev server in isolated subprocess to avoid React version conflicts
|
|
76
|
+
// File listing and progress bars are handled within the subprocess
|
|
77
|
+
spawnDevServer({
|
|
78
|
+
absoluteSrc,
|
|
79
|
+
accountName: derivedAccountId?.toString(),
|
|
80
|
+
noSsl,
|
|
81
|
+
port,
|
|
82
|
+
generateFieldsTypes,
|
|
135
83
|
resetSession: resetSession || false,
|
|
136
|
-
startProgressBar,
|
|
137
84
|
dest,
|
|
138
85
|
});
|
|
139
86
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ChildProcess } from 'child_process';
|
|
2
|
+
interface DevServerOptions {
|
|
3
|
+
absoluteSrc: string;
|
|
4
|
+
accountName?: string;
|
|
5
|
+
configPath?: string;
|
|
6
|
+
noSsl?: boolean;
|
|
7
|
+
port?: number;
|
|
8
|
+
generateFieldsTypes?: boolean;
|
|
9
|
+
resetSession?: boolean;
|
|
10
|
+
dest?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function spawnDevServer(options: DevServerOptions): ChildProcess;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { spawn, execSync } from 'child_process';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { getConfigFilePath } from '@hubspot/local-dev-lib/config';
|
|
7
|
+
/**
|
|
8
|
+
* Ensures cms-dev-server is installed in an isolated cache directory.
|
|
9
|
+
* This prevents React version conflicts with the CLI.
|
|
10
|
+
*/
|
|
11
|
+
function ensureCmsDevServerCache(targetVersion) {
|
|
12
|
+
const cacheDir = path.join(os.homedir(), '.hubspot', 'cms-dev-server-cache');
|
|
13
|
+
const packageJsonPath = path.join(cacheDir, 'node_modules', '@hubspot', 'cms-dev-server', 'package.json');
|
|
14
|
+
// Check if already installed with correct version
|
|
15
|
+
let needsInstall = true;
|
|
16
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
17
|
+
try {
|
|
18
|
+
const installedPackage = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
19
|
+
if (installedPackage.version === targetVersion) {
|
|
20
|
+
needsInstall = false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
// If we can't read the package.json, reinstall
|
|
25
|
+
needsInstall = true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (needsInstall) {
|
|
29
|
+
console.log(`Setting up isolated cms-dev-server ${targetVersion}...`);
|
|
30
|
+
// Create cache directory
|
|
31
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
32
|
+
// Clear old installation if exists
|
|
33
|
+
const nodeModulesDir = path.join(cacheDir, 'node_modules');
|
|
34
|
+
if (fs.existsSync(nodeModulesDir)) {
|
|
35
|
+
fs.rmSync(nodeModulesDir, { recursive: true, force: true });
|
|
36
|
+
}
|
|
37
|
+
// Install cms-dev-server with production dependencies only
|
|
38
|
+
try {
|
|
39
|
+
execSync(`npm install @hubspot/cms-dev-server@${targetVersion} --production --no-save --loglevel=error`, {
|
|
40
|
+
cwd: cacheDir,
|
|
41
|
+
stdio: 'ignore', // Suppress npm output
|
|
42
|
+
});
|
|
43
|
+
console.log('✓ cms-dev-server setup complete');
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
console.error('Failed to install cms-dev-server:', e);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return cacheDir;
|
|
51
|
+
}
|
|
52
|
+
export function spawnDevServer(options) {
|
|
53
|
+
const { absoluteSrc, accountName, noSsl, port, generateFieldsTypes, resetSession, dest, } = options;
|
|
54
|
+
// Get the version from CLI's package.json
|
|
55
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
56
|
+
const cliPackageJsonPath = path.join(__dirname, '../../package.json');
|
|
57
|
+
const cliPackageJson = JSON.parse(fs.readFileSync(cliPackageJsonPath, 'utf8'));
|
|
58
|
+
const targetVersion = cliPackageJson.dependencies['@hubspot/cms-dev-server'];
|
|
59
|
+
if (!targetVersion) {
|
|
60
|
+
console.error('Could not determine cms-dev-server version from package.json');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
// Ensure cms-dev-server is installed in isolated cache
|
|
64
|
+
const cacheDir = ensureCmsDevServerCache(targetVersion);
|
|
65
|
+
// Build a Node script that imports and calls createDevServer
|
|
66
|
+
// This runs in the isolated cache directory, completely separate from CLI's node_modules
|
|
67
|
+
const script = `
|
|
68
|
+
// Suppress library deprecation warnings (e.g., body-parser)
|
|
69
|
+
process.noDeprecation = true;
|
|
70
|
+
|
|
71
|
+
const { createDevServer } = await import('@hubspot/cms-dev-server');
|
|
72
|
+
const { walk } = await import('@hubspot/local-dev-lib/fs');
|
|
73
|
+
const { createIgnoreFilter } = await import('@hubspot/local-dev-lib/ignoreRules');
|
|
74
|
+
const { isAllowedExtension } = await import('@hubspot/local-dev-lib/path');
|
|
75
|
+
const { FILE_UPLOAD_RESULT_TYPES } = await import('@hubspot/local-dev-lib/constants/files');
|
|
76
|
+
const cliProgress = (await import('cli-progress')).default;
|
|
77
|
+
|
|
78
|
+
${dest
|
|
79
|
+
? `
|
|
80
|
+
// Get uploadable files for preview
|
|
81
|
+
let filePaths = [];
|
|
82
|
+
try {
|
|
83
|
+
filePaths = await walk(${JSON.stringify(absoluteSrc)});
|
|
84
|
+
} catch (e) {
|
|
85
|
+
console.error('Error walking directory:', e);
|
|
86
|
+
}
|
|
87
|
+
filePaths = filePaths
|
|
88
|
+
.filter(file => isAllowedExtension(file))
|
|
89
|
+
.filter(createIgnoreFilter(false));
|
|
90
|
+
|
|
91
|
+
// Create progress bar for initial upload
|
|
92
|
+
function startProgressBar(numFiles) {
|
|
93
|
+
const initialUploadProgressBar = new cliProgress.SingleBar(
|
|
94
|
+
{
|
|
95
|
+
gracefulExit: true,
|
|
96
|
+
format: '[{bar}] {percentage}% | {value}/{total} | {label}',
|
|
97
|
+
hideCursor: true,
|
|
98
|
+
},
|
|
99
|
+
cliProgress.Presets.rect
|
|
100
|
+
);
|
|
101
|
+
initialUploadProgressBar.start(numFiles, 0, {
|
|
102
|
+
label: 'Preparing upload...',
|
|
103
|
+
});
|
|
104
|
+
let uploadsHaveStarted = false;
|
|
105
|
+
return {
|
|
106
|
+
onAttemptCallback: () => {},
|
|
107
|
+
onSuccessCallback: () => {
|
|
108
|
+
initialUploadProgressBar.increment();
|
|
109
|
+
if (!uploadsHaveStarted) {
|
|
110
|
+
uploadsHaveStarted = true;
|
|
111
|
+
initialUploadProgressBar.update(0, {
|
|
112
|
+
label: 'Uploading files...',
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
onFirstErrorCallback: () => {},
|
|
117
|
+
onRetryCallback: () => {},
|
|
118
|
+
onFinalErrorCallback: () => initialUploadProgressBar.increment(),
|
|
119
|
+
onFinishCallback: (results) => {
|
|
120
|
+
initialUploadProgressBar.update(numFiles, {
|
|
121
|
+
label: 'Upload complete',
|
|
122
|
+
});
|
|
123
|
+
initialUploadProgressBar.stop();
|
|
124
|
+
results.forEach(result => {
|
|
125
|
+
if (result.resultType == FILE_UPLOAD_RESULT_TYPES.FAILURE) {
|
|
126
|
+
console.error(\`Failed to upload \${result.file}\`);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const themePreviewOptions = {
|
|
134
|
+
filePaths,
|
|
135
|
+
startProgressBar,
|
|
136
|
+
resetSession: ${Boolean(resetSession)},
|
|
137
|
+
dest: ${JSON.stringify(dest)},
|
|
138
|
+
};
|
|
139
|
+
`
|
|
140
|
+
: 'const themePreviewOptions = undefined;'}
|
|
141
|
+
|
|
142
|
+
createDevServer(
|
|
143
|
+
${JSON.stringify(absoluteSrc)},
|
|
144
|
+
false, // storybook
|
|
145
|
+
'', // config (uses env var HUBSPOT_CONFIG_PATH)
|
|
146
|
+
${JSON.stringify(accountName || '')},
|
|
147
|
+
${!noSsl}, // sslEnabled
|
|
148
|
+
${Boolean(generateFieldsTypes)}, // fieldGenEnabled
|
|
149
|
+
themePreviewOptions
|
|
150
|
+
);
|
|
151
|
+
`;
|
|
152
|
+
// Set environment variables
|
|
153
|
+
const env = { ...process.env };
|
|
154
|
+
if (port) {
|
|
155
|
+
env.PORT = port.toString();
|
|
156
|
+
}
|
|
157
|
+
// Suppress Node.js deprecation warnings
|
|
158
|
+
env.NODE_NO_WARNINGS = '1';
|
|
159
|
+
// Set config path so cms-dev-server can find hubspot.config.yaml
|
|
160
|
+
// Use existing env var if set, otherwise get the default config path
|
|
161
|
+
if (!env.HUBSPOT_CONFIG_PATH) {
|
|
162
|
+
try {
|
|
163
|
+
env.HUBSPOT_CONFIG_PATH = getConfigFilePath();
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
// Config file doesn't exist - cms-dev-server will handle this gracefully
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
console.log(env.HUBSPOT_CONFIG_PATH);
|
|
170
|
+
// Spawn Node with the inline script from the isolated cache directory
|
|
171
|
+
// This ensures complete isolation from CLI's React 19
|
|
172
|
+
const devServer = spawn('node', ['--input-type=module', '-e', script], {
|
|
173
|
+
stdio: 'inherit',
|
|
174
|
+
env,
|
|
175
|
+
cwd: cacheDir,
|
|
176
|
+
});
|
|
177
|
+
// Handle process events
|
|
178
|
+
devServer.on('error', error => {
|
|
179
|
+
console.error('Failed to start dev server:', error);
|
|
180
|
+
process.exit(1);
|
|
181
|
+
});
|
|
182
|
+
devServer.on('exit', (code, signal) => {
|
|
183
|
+
if (code !== 0 && code !== null) {
|
|
184
|
+
console.error(`Dev server exited with code ${code}`);
|
|
185
|
+
process.exit(code);
|
|
186
|
+
}
|
|
187
|
+
if (signal) {
|
|
188
|
+
console.error(`Dev server killed with signal ${signal}`);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
// Handle CLI termination
|
|
193
|
+
process.on('SIGINT', () => {
|
|
194
|
+
devServer.kill('SIGINT');
|
|
195
|
+
});
|
|
196
|
+
process.on('SIGTERM', () => {
|
|
197
|
+
devServer.kill('SIGTERM');
|
|
198
|
+
});
|
|
199
|
+
return devServer;
|
|
200
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "8.0.10-experimental.
|
|
3
|
+
"version": "8.0.10-experimental.1",
|
|
4
4
|
"description": "The official CLI for developing on HubSpot",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": "https://github.com/HubSpot/hubspot-cli",
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
"open": "7.4.2",
|
|
31
31
|
"p-queue": "8.1.0",
|
|
32
32
|
"react": "19.2.3",
|
|
33
|
-
"react-dom": "19.2.3",
|
|
34
33
|
"strip-ansi": "7.1.0",
|
|
35
34
|
"table": "6.9.0",
|
|
36
35
|
"tmp": "0.2.4",
|
|
@@ -119,11 +118,7 @@
|
|
|
119
118
|
"access": "public",
|
|
120
119
|
"registry": "https://registry.npmjs.org/"
|
|
121
120
|
},
|
|
122
|
-
"bundledDependencies": [
|
|
123
|
-
"@hubspot/cms-dev-server"
|
|
124
|
-
],
|
|
125
121
|
"resolutions": {
|
|
126
|
-
"eslint-visitor-keys": "4.2.0"
|
|
127
|
-
"@hubspot/cms-dev-server/react": "18.3.1"
|
|
122
|
+
"eslint-visitor-keys": "4.2.0"
|
|
128
123
|
}
|
|
129
124
|
}
|