@nu-art/build-and-install 0.401.9 → 0.500.6
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/BuildAndInstall.d.ts +2 -2
- package/BuildAndInstall.js +10 -2
- package/config/consts.d.ts +2 -2
- package/config/consts.js +1 -1
- package/config/package/consts.d.ts +1 -1
- package/config/types/package/runtime-package.d.ts +1 -1
- package/config/types/project-config.d.ts +17 -2
- package/core/FilesCache.d.ts +5 -1
- package/core/FilesCache.js +5 -1
- package/core/Unit_HelpPrinter.d.ts +4 -7
- package/core/Unit_HelpPrinter.js +3 -11
- package/core/params.d.ts +2 -1
- package/core/params.js +12 -3
- package/core/types.d.ts +2 -2
- package/dependencies/UnitsDependencyMapper.d.ts +8 -0
- package/dependencies/UnitsDependencyMapper.js +58 -4
- package/exceptions/UnitPhaseException.d.ts +1 -1
- package/exports/IndicesMcpServer.js +1 -1
- package/package.json +5 -5
- package/phases/PhaseManager.d.ts +2 -2
- package/phases/PhaseManager.js +4 -4
- package/phases/definitions/consts.d.ts +3 -0
- package/phases/definitions/consts.js +7 -0
- package/phases/definitions/types.d.ts +1 -1
- package/templates/backend/proxy/proxy._ts +36 -31
- package/templates/firebase/config/database.rules.json +6 -0
- package/units/base/BaseUnit.d.ts +1 -1
- package/units/discovery/UnitsMapper.d.ts +3 -2
- package/units/discovery/resolvers/UnitMapper_Base.d.ts +2 -2
- package/units/discovery/resolvers/UnitMapper_FirebaseFunction.d.ts +12 -1
- package/units/discovery/resolvers/UnitMapper_FirebaseFunction.js +48 -18
- package/units/discovery/resolvers/UnitMapper_FirebaseHosting.d.ts +5 -9
- package/units/discovery/resolvers/UnitMapper_FirebaseHosting.js +3 -1
- package/units/discovery/resolvers/UnitMapper_Node.d.ts +1 -1
- package/units/discovery/resolvers/UnitMapper_Node.js +8 -15
- package/units/discovery/resolvers/UnitMapper_ViteHosting.d.ts +46 -0
- package/units/discovery/resolvers/UnitMapper_ViteHosting.js +59 -0
- package/units/implementations/Unit_NodeProject.d.ts +3 -2
- package/units/implementations/Unit_NodeProject.js +30 -6
- package/units/implementations/Unit_PackageJson.d.ts +8 -2
- package/units/implementations/Unit_PackageJson.js +46 -11
- package/units/implementations/Unit_TypescriptLib.d.ts +8 -2
- package/units/implementations/Unit_TypescriptLib.js +155 -4
- package/units/implementations/firebase/Unit_FirebaseFunctionsApp.d.ts +12 -2
- package/units/implementations/firebase/Unit_FirebaseFunctionsApp.js +73 -17
- package/units/implementations/firebase/Unit_FirebaseHostingApp.d.ts +19 -97
- package/units/implementations/firebase/Unit_FirebaseHostingApp.js +28 -290
- package/units/implementations/firebase/Unit_HostingApp.d.ts +59 -0
- package/units/implementations/firebase/Unit_HostingApp.js +225 -0
- package/units/implementations/firebase/Unit_ViteHostingApp.d.ts +10 -0
- package/units/implementations/firebase/Unit_ViteHostingApp.js +28 -0
- package/workspace/Workspace.d.ts +3 -1
- package/workspace/Workspace.js +2 -1
- package/config/types/configs/index.d.ts +0 -3
- package/config/types/configs/index.js +0 -3
- package/config/types/index.d.ts +0 -4
- package/config/types/index.js +0 -4
- package/config/types/package/index.d.ts +0 -2
- package/config/types/package/index.js +0 -2
- package/phases/definitions/index.d.ts +0 -2
- package/phases/definitions/index.js +0 -2
- package/phases/index.d.ts +0 -2
- package/phases/index.js +0 -2
- package/units/discovery/resolvers/index.d.ts +0 -4
- package/units/discovery/resolvers/index.js +0 -4
- package/units/index.d.ts +0 -6
- package/units/index.js +0 -6
|
@@ -1,110 +1,45 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CONST_DeployHostingDir, CONST_DeploymentMetadata, CONST_FirebaseJSON, CONST_FirebaseRC, CONST_HostingBuildTarball, CONST_StagingDir, CONST_TrashDir, CONST_VersionApp } from '../../../config/consts.js';
|
|
1
|
+
import { LogLevel } from '@nu-art/ts-common';
|
|
3
2
|
import { Commando_Basic, Commando_NVM, CommandoException } from '@nu-art/commando';
|
|
3
|
+
import { Unit_HostingApp } from './Unit_HostingApp.js';
|
|
4
4
|
import { resolve } from 'path';
|
|
5
|
-
import { Unit_TypescriptLib } from '../Unit_TypescriptLib.js';
|
|
6
|
-
import { deployLogFilter, ensureArtifactRegistryRepository } from './common.js';
|
|
7
5
|
import { FileSystemUtils } from '@nu-art/ts-common/utils/FileSystemUtils';
|
|
8
6
|
/**
|
|
9
|
-
* Firebase Hosting application unit.
|
|
10
|
-
*
|
|
11
|
-
* **Key Features**:
|
|
12
|
-
* - Extends Unit_TypescriptLib (compiles TypeScript)
|
|
13
|
-
* - Manages Firebase hosting configuration (firebase.json, .firebaserc)
|
|
14
|
-
* - Supports multiple environments (local, staging, production)
|
|
15
|
-
* - Implements launch and deploy phases
|
|
16
|
-
*
|
|
17
|
-
* **Phases Implemented**:
|
|
18
|
-
* - `prepare()`: Resolves Firebase hosting config files
|
|
19
|
-
* - `compile()`: Compiles TypeScript (without declarations)
|
|
20
|
-
* - `launch()`: Starts Firebase hosting emulator
|
|
21
|
-
* - `deploy()`: Deploys to Firebase hosting
|
|
22
|
-
*
|
|
23
|
-
* **Configuration**:
|
|
24
|
-
* - `servingPort`: Port for local hosting server
|
|
25
|
-
* - `hostingConfig`: Firebase hosting configuration (public folder, rewrites)
|
|
26
|
-
* - `envConfig`: Environment-specific config (projectId, isLocal)
|
|
7
|
+
* Firebase Hosting application unit (webpack bundler).
|
|
8
|
+
* Extends Unit_HostingApp; implements compile via npm run build, launch via npm run start.
|
|
27
9
|
*/
|
|
28
|
-
export class Unit_FirebaseHostingApp extends
|
|
29
|
-
|
|
30
|
-
injectedMetadata = {};
|
|
31
|
-
static DefaultConfig_FirebaseHosting = {
|
|
32
|
-
servingPort: 8100,
|
|
33
|
-
output: 'dist',
|
|
34
|
-
};
|
|
10
|
+
export class Unit_FirebaseHostingApp extends Unit_HostingApp {
|
|
11
|
+
static DefaultConfig_FirebaseHosting = Unit_HostingApp.DefaultConfig_Hosting;
|
|
35
12
|
constructor(config) {
|
|
36
13
|
super(config);
|
|
37
14
|
this.addToClassStack(Unit_FirebaseHostingApp);
|
|
38
15
|
}
|
|
39
|
-
//######################### Phase Implementations #########################
|
|
40
16
|
async prepare() {
|
|
41
17
|
await super.prepare();
|
|
42
|
-
await this.
|
|
43
|
-
await this.resolveHostingJSON();
|
|
44
|
-
await this.resolveHostingRuntimeConfig();
|
|
18
|
+
await this.resolveWebpackEnvConfig();
|
|
45
19
|
}
|
|
46
|
-
async
|
|
47
|
-
await this.resolveTSConfig(resolve(this.config.fullPath, './src'), 'main', { compilerOptions: { declaration: false } });
|
|
48
|
-
await this.clearOutputDir();
|
|
49
|
-
await this.createAppVersionFile();
|
|
50
|
-
await this.compileImpl();
|
|
51
|
-
}
|
|
52
|
-
async launch() {
|
|
53
|
-
this.setStatus('Launching');
|
|
54
|
-
await this.releaseWebpackPorts();
|
|
55
|
-
await this.runApp();
|
|
56
|
-
}
|
|
57
|
-
async releaseWebpackPorts() {
|
|
58
|
-
return this.releasePorts([`${this.config.servingPort}`]);
|
|
59
|
-
}
|
|
60
|
-
async deploy() {
|
|
61
|
-
const commando = this.allocateCommando(Commando_NVM).applyNVM()
|
|
62
|
-
.cd(this.config.fullPath)
|
|
63
|
-
.setLogLevelFilter(deployLogFilter)
|
|
64
|
-
// example: Function URL (hello(us-central1)): https://hello-kv65k7yylq-uc.a.run.app
|
|
65
|
-
.onLog(/.*Hosting URL.*(https:\/\/.*?)$/, match => {
|
|
66
|
-
this.hosting[match[1]] = match[2];
|
|
67
|
-
});
|
|
68
|
-
const debug = this.runtimeContext.runtimeParams.verbose ? ' --debug' : '';
|
|
69
|
-
await this.executeAsyncCommando(commando, `${this.npmCommand('firebase')}${debug} deploy --only hosting`);
|
|
70
|
-
}
|
|
71
|
-
//######################### ResolveConfig Logic #########################
|
|
72
|
-
getEnvConfig() {
|
|
73
|
-
const envConfig = this.config.envConfig;
|
|
74
|
-
if (!envConfig)
|
|
75
|
-
throw new ImplementationMissingException(`Missing EnvConfig in unit ${this.config.label}`);
|
|
76
|
-
return envConfig;
|
|
77
|
-
}
|
|
78
|
-
async resolveHostingRC() {
|
|
20
|
+
async resolveWebpackEnvConfig() {
|
|
79
21
|
const envConfig = this.getEnvConfig();
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
await FileSystemUtils.file.write.json(targetPath, fileContent);
|
|
100
|
-
}
|
|
101
|
-
async resolveHostingRuntimeConfig() {
|
|
102
|
-
const envConfig = this.getEnvConfig().config;
|
|
103
|
-
const targetPath = resolve(this.config.fullPath, `./src/main/config.ts`);
|
|
104
|
-
const fileContent = `export const config = ${JSON.stringify(envConfig, null, 2)};`;
|
|
22
|
+
const wp = envConfig.webpackConfig;
|
|
23
|
+
const minifyHtml = wp?.minifyHtml ?? false;
|
|
24
|
+
const devServerSSL = wp?.devServerSSL ?? false;
|
|
25
|
+
const devServerPort = wp?.devServerPort ?? this.config.servingPort;
|
|
26
|
+
const sslKey = wp?.sslKey ? `"${wp.sslKey}"` : 'undefined';
|
|
27
|
+
const sslCert = wp?.sslCert ? `"${wp.sslCert}"` : 'undefined';
|
|
28
|
+
const envName = this.runtimeContext.runtimeParams.environment ?? 'local';
|
|
29
|
+
const targetPath = resolve(this.config.fullPath, 'webpack-env.generated.ts');
|
|
30
|
+
const fileContent = [
|
|
31
|
+
`/** Generated by BAI during prepare - do not edit */`,
|
|
32
|
+
`export const webpackEnvConfig = {`,
|
|
33
|
+
` envName: "${envName}",`,
|
|
34
|
+
` minifyHtml: ${minifyHtml},`,
|
|
35
|
+
` devServerSSL: ${devServerSSL},`,
|
|
36
|
+
` devServerPort: ${devServerPort},`,
|
|
37
|
+
` sslKey: ${sslKey},`,
|
|
38
|
+
` sslCert: ${sslCert},`,
|
|
39
|
+
`};\n`,
|
|
40
|
+
].join('\n');
|
|
105
41
|
await FileSystemUtils.file.write(targetPath, fileContent);
|
|
106
42
|
}
|
|
107
|
-
//######################### Compile Logic #########################
|
|
108
43
|
async compileImpl() {
|
|
109
44
|
const commando = this.allocateCommando(Commando_NVM, Commando_Basic).applyNVM()
|
|
110
45
|
.cd(this.config.fullPath);
|
|
@@ -113,212 +48,15 @@ export class Unit_FirebaseHostingApp extends Unit_TypescriptLib {
|
|
|
113
48
|
throw new CommandoException(`Error compiling`, stdout, stderr, exitCode);
|
|
114
49
|
});
|
|
115
50
|
}
|
|
116
|
-
async createAppVersionFile() {
|
|
117
|
-
//Writing the file to the package source instead of the output is fine,
|
|
118
|
-
//Webpack bundles files into the output automatically!
|
|
119
|
-
const targetPath = `${this.config.fullPath}/src/main/${CONST_VersionApp}`;
|
|
120
|
-
const appVersion = this.runtimeContext.version;
|
|
121
|
-
await FileSystemUtils.file.write.json(targetPath, { version: appVersion });
|
|
122
|
-
}
|
|
123
|
-
//######################### Launch Logic #########################
|
|
124
51
|
async runApp() {
|
|
125
52
|
const commando = this.allocateCommando(Commando_NVM).applyNVM()
|
|
126
53
|
.setUID(this.config.key)
|
|
127
54
|
.cd(this.config.fullPath)
|
|
128
|
-
.setLogLevelFilter((log
|
|
55
|
+
.setLogLevelFilter((log) => {
|
|
129
56
|
if (log.toLowerCase().includes('<i>'))
|
|
130
57
|
return LogLevel.Info;
|
|
131
58
|
});
|
|
132
59
|
await this.executeAsyncCommando(commando, 'npm run start');
|
|
133
60
|
this.logWarning('HOSTING TERMINATED');
|
|
134
61
|
}
|
|
135
|
-
//######################### Build Push Image Phase #########################
|
|
136
|
-
/**
|
|
137
|
-
* Builds hosting output and uploads it to Artifact Registry as a generic package.
|
|
138
|
-
*
|
|
139
|
-
* **Process**:
|
|
140
|
-
* 1. Validates hostingDeployment config exists
|
|
141
|
-
* 2. Creates deployment-metadata.json with build information
|
|
142
|
-
* 3. Creates tarball of hosting output directory
|
|
143
|
-
* 4. Uploads to Artifact Registry as generic package
|
|
144
|
-
*
|
|
145
|
-
* **Requirements**:
|
|
146
|
-
* - `--build-push-image <tag>` CLI flag with tag value
|
|
147
|
-
* - `hostingDeployment` config in unit config with `packageName` field
|
|
148
|
-
* - `packageName` must comply with Artifact Registry naming restrictions
|
|
149
|
-
* - gcloud CLI installed and authenticated
|
|
150
|
-
* - Artifact Registry API enabled in GCP project
|
|
151
|
-
*/
|
|
152
|
-
async buildPushImage() {
|
|
153
|
-
const hostingDeployment = this.config.hostingDeployment;
|
|
154
|
-
if (!hostingDeployment) {
|
|
155
|
-
throw new ImplementationMissingException(`Missing hostingDeployment config in unit ${this.config.key}`);
|
|
156
|
-
}
|
|
157
|
-
const buildTag = this.runtimeContext.runtimeParams.buildPushImage;
|
|
158
|
-
if (!buildTag) {
|
|
159
|
-
throw new ImplementationMissingException(`Missing buildPushImage runtime param in unit ${this.config.key}`);
|
|
160
|
-
}
|
|
161
|
-
const artifactRegistry = hostingDeployment.artifactRegistry;
|
|
162
|
-
const packageName = hostingDeployment.packageName;
|
|
163
|
-
if (!packageName) {
|
|
164
|
-
throw new ImplementationMissingException(`Missing packageName in hostingDeployment config for unit ${this.config.key}`);
|
|
165
|
-
}
|
|
166
|
-
this.logInfo(`Building and uploading hosting package to Artifact Registry:`);
|
|
167
|
-
this.logInfo(` Package: ${packageName}`);
|
|
168
|
-
this.logInfo(` Tag: ${buildTag}`);
|
|
169
|
-
// Check for dry run mode
|
|
170
|
-
if (this.runtimeContext.runtimeParams.dryRun) {
|
|
171
|
-
this.logInfo(`[DRY RUN] Would build and upload hosting package: ${packageName}:${buildTag}`);
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
// Ensure Artifact Registry repository exists
|
|
175
|
-
const commando = this.allocateCommando();
|
|
176
|
-
await ensureArtifactRegistryRepository(commando, artifactRegistry, 'generic', this);
|
|
177
|
-
// Create deployment-metadata.json in output directory
|
|
178
|
-
const metadata = {
|
|
179
|
-
...this.injectedMetadata,
|
|
180
|
-
'build.timestamp': new Date().toISOString(),
|
|
181
|
-
'build.tag': buildTag,
|
|
182
|
-
'build.project': artifactRegistry.projectId,
|
|
183
|
-
'build.package-name': packageName,
|
|
184
|
-
'version': this.runtimeContext.version,
|
|
185
|
-
'git.commit': process.env.GIT_COMMIT || '',
|
|
186
|
-
'git.branch': process.env.GIT_BRANCH || '',
|
|
187
|
-
'build.user': process.env.USER || '',
|
|
188
|
-
};
|
|
189
|
-
this.logDebug(`Metadata: `, metadata);
|
|
190
|
-
// Create staging directory for tarball contents
|
|
191
|
-
const buildOutputDir = resolve(this.config.fullPath, CONST_TrashDir);
|
|
192
|
-
const stagingDir = resolve(buildOutputDir, CONST_StagingDir);
|
|
193
|
-
await FileSystemUtils.folder.delete(stagingDir);
|
|
194
|
-
await FileSystemUtils.folder.create(stagingDir);
|
|
195
|
-
const tarballPath = resolve(buildOutputDir, CONST_HostingBuildTarball);
|
|
196
|
-
// Copy all files to staging directory
|
|
197
|
-
const outputDirName = resolve(this.config.output).split('/').pop() || 'dist';
|
|
198
|
-
// Copy firebase.json, .firebaserc, dist folder, and create deployment-metadata.json
|
|
199
|
-
await FileSystemUtils.folder.copy(this.config.output, resolve(stagingDir, outputDirName));
|
|
200
|
-
await FileSystemUtils.file.write.json(resolve(stagingDir, CONST_DeploymentMetadata), metadata);
|
|
201
|
-
// Create tarball from staging directory contents
|
|
202
|
-
// Note: Use explicit file list to include hidden files (.*) which * wildcard doesn't match
|
|
203
|
-
commando.cd(stagingDir);
|
|
204
|
-
await this.executeAsyncCommando(commando, `tar -czf ${tarballPath} ${CONST_DeploymentMetadata} ${outputDirName}`, (stdout, stderr, exitCode) => {
|
|
205
|
-
if (exitCode !== 0)
|
|
206
|
-
throw new CommandoException(`Failed to create tarball (exit code ${exitCode})`, stdout, stderr, exitCode);
|
|
207
|
-
});
|
|
208
|
-
this.logInfo(`Created tarball: ${tarballPath}`);
|
|
209
|
-
// Upload to Artifact Registry
|
|
210
|
-
const region = artifactRegistry.region;
|
|
211
|
-
const repository = artifactRegistry.repository;
|
|
212
|
-
const projectId = artifactRegistry.projectId;
|
|
213
|
-
// Upload file - package and version are created automatically if they don't exist
|
|
214
|
-
// Note: Generic packages don't support "latest" version like Docker images
|
|
215
|
-
// The build tag should be used for deployment (defaults to 'latest' if not specified)
|
|
216
|
-
await this.executeAsyncCommando(commando, `gcloud artifacts generic upload --package=${packageName} --version=${buildTag} --source=${tarballPath} --location=${region} --repository=${repository} --project=${projectId}`, (stdout, stderr, exitCode) => {
|
|
217
|
-
if (exitCode !== 0)
|
|
218
|
-
throw new CommandoException(`Failed to upload hosting package to Artifact Registry (exit code ${exitCode})`, stdout, stderr, exitCode);
|
|
219
|
-
});
|
|
220
|
-
this.logInfo(`Successfully uploaded hosting package: ${packageName}:${buildTag} and ${packageName}:latest`);
|
|
221
|
-
}
|
|
222
|
-
//######################### Deploy Image Phase #########################
|
|
223
|
-
/**
|
|
224
|
-
* Deploys hosting build from Artifact Registry to Firebase Hosting.
|
|
225
|
-
*
|
|
226
|
-
* **Process**:
|
|
227
|
-
* 1. Validates hostingDeployment config exists
|
|
228
|
-
* 2. Downloads tarball from Artifact Registry
|
|
229
|
-
* 3. Extracts to temp directory
|
|
230
|
-
* 4. Sets up Firebase tools (package.json + npm install)
|
|
231
|
-
* 5. Deploys to Firebase Hosting
|
|
232
|
-
* 6. Validates deployment by fetching deployment-metadata.json
|
|
233
|
-
*
|
|
234
|
-
* **Requirements**:
|
|
235
|
-
* - `--deploy-image <tag>` CLI flag with tag value
|
|
236
|
-
* - `hostingDeployment` config in unit config with `packageName` field
|
|
237
|
-
* - Package must already exist in Artifact Registry (built via buildPushImage)
|
|
238
|
-
* - gcloud CLI installed and authenticated
|
|
239
|
-
* - Firebase CLI (installed via npm in temp directory)
|
|
240
|
-
*/
|
|
241
|
-
async deployImage() {
|
|
242
|
-
const hostingDeployment = this.config.hostingDeployment;
|
|
243
|
-
if (!hostingDeployment) {
|
|
244
|
-
throw new ImplementationMissingException(`Missing hostingDeployment config in unit ${this.config.key}`);
|
|
245
|
-
}
|
|
246
|
-
const deployTag = this.runtimeContext.runtimeParams.deployImage;
|
|
247
|
-
if (!deployTag) {
|
|
248
|
-
throw new ImplementationMissingException(`Missing deployImage runtime param in unit ${this.config.key}. Generic packages require a specific version tag (cannot use 'latest')`);
|
|
249
|
-
}
|
|
250
|
-
const artifactRegistry = hostingDeployment.artifactRegistry;
|
|
251
|
-
const packageName = hostingDeployment.packageName;
|
|
252
|
-
if (!packageName) {
|
|
253
|
-
throw new ImplementationMissingException(`Missing packageName in hostingDeployment config for unit ${this.config.key}`);
|
|
254
|
-
}
|
|
255
|
-
const region = artifactRegistry.region;
|
|
256
|
-
const repository = artifactRegistry.repository;
|
|
257
|
-
const projectId = artifactRegistry.projectId;
|
|
258
|
-
this.logInfo(`Deploying hosting package: ${packageName}:${deployTag}`);
|
|
259
|
-
// Check for dry run mode
|
|
260
|
-
if (this.runtimeContext.runtimeParams.dryRun) {
|
|
261
|
-
this.logInfo(`[DRY RUN] Would deploy hosting package: ${packageName}:${deployTag}`);
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
// Setup temp directory for deployment
|
|
265
|
-
const deployTempDir = resolve(this.config.fullPath, `${CONST_TrashDir}/${CONST_DeployHostingDir}`);
|
|
266
|
-
this.logInfo(`Setting up deployment directory: ${deployTempDir}`);
|
|
267
|
-
await FileSystemUtils.folder.delete(deployTempDir);
|
|
268
|
-
await FileSystemUtils.folder.create(deployTempDir);
|
|
269
|
-
const commando = this.allocateCommando(Commando_NVM)
|
|
270
|
-
.applyNVM()
|
|
271
|
-
.cd(deployTempDir)
|
|
272
|
-
.mark();
|
|
273
|
-
// Download tarball from Artifact Registry
|
|
274
|
-
// Note: --destination must be a directory, not a file path
|
|
275
|
-
this.logInfo(`Downloading hosting package from Artifact Registry from: ${projectId}/${repository}/${packageName}/${deployTag}`);
|
|
276
|
-
await this.executeAsyncCommando(commando, `gcloud artifacts generic download --package=${packageName} --version=${deployTag} --destination=${deployTempDir} --location=${region} --repository=${repository} --project=${projectId}`, (stdout, stderr, exitCode) => {
|
|
277
|
-
if (exitCode !== 0)
|
|
278
|
-
throw new CommandoException(`Failed to download hosting package from Artifact Registry (exit code ${exitCode})`, stdout, stderr, exitCode);
|
|
279
|
-
});
|
|
280
|
-
// Find the downloaded file (gcloud downloads with auto-generated name based on package and version)
|
|
281
|
-
// The file will be named: {packageName}-{version}.tar.gz
|
|
282
|
-
this.logInfo(`Locating downloaded tarball...`);
|
|
283
|
-
const downloadedFiles = await FileSystemUtils.folder.list(deployTempDir);
|
|
284
|
-
const tarballFile = downloadedFiles.find(file => file.endsWith('.tar.gz'));
|
|
285
|
-
if (!tarballFile)
|
|
286
|
-
throw new ImplementationMissingException(`Downloaded tarball not found in ${deployTempDir}. Files found: ${downloadedFiles.join(', ')}`);
|
|
287
|
-
const tarballPath = resolve(deployTempDir, tarballFile);
|
|
288
|
-
this.logDebug(`Downloaded tarball: ${tarballPath}`);
|
|
289
|
-
// Extract tarball directly to deployTempDir (contains firebase.json, .firebaserc, and dist/)
|
|
290
|
-
this.logInfo(`Extracting hosting package...`);
|
|
291
|
-
this.logInfo(`Extracting hosting package...`);
|
|
292
|
-
await this.executeAsyncCommando(commando, `tar -xzf ${tarballPath} -C ${deployTempDir}`, (stdout, stderr, exitCode) => {
|
|
293
|
-
if (exitCode !== 0) {
|
|
294
|
-
throw new CommandoException(`Failed to extract tarball (exit code ${exitCode})`, stdout, stderr, exitCode);
|
|
295
|
-
}
|
|
296
|
-
});
|
|
297
|
-
this.logInfo(`Extracted hosting package to: ${deployTempDir}`);
|
|
298
|
-
this.logInfo(`Copying firebase configs..`);
|
|
299
|
-
const firebaseJsonPath = resolve(this.config.fullPath, CONST_FirebaseJSON);
|
|
300
|
-
const firebaseRcPath = resolve(this.config.fullPath, CONST_FirebaseRC);
|
|
301
|
-
await FileSystemUtils.file.copy(firebaseJsonPath, resolve(deployTempDir, CONST_FirebaseJSON));
|
|
302
|
-
await FileSystemUtils.file.copy(firebaseRcPath, resolve(deployTempDir, CONST_FirebaseRC));
|
|
303
|
-
this.logDebug(`Copied firebase configs!`);
|
|
304
|
-
// firebase.json and .firebaserc are already in deployTempDir from tarball extraction
|
|
305
|
-
// Deploy using firebase CLI
|
|
306
|
-
const envConfig = this.getEnvConfig();
|
|
307
|
-
this.logInfo(`Deploying to Firebase Hosting: ${deployTempDir} => ${envConfig.projectId}`);
|
|
308
|
-
const deployCommando = this.allocateCommando(Commando_NVM).applyNVM()
|
|
309
|
-
.cd(deployTempDir)
|
|
310
|
-
.setLogLevelFilter(deployLogFilter)
|
|
311
|
-
.onLog(/.*Hosting URL.*(https:\/\/.*?)$/, match => {
|
|
312
|
-
this.hosting[match[1]] = match[2];
|
|
313
|
-
});
|
|
314
|
-
const debug = this.runtimeContext.runtimeParams.verbose ? ' --debug' : '';
|
|
315
|
-
await this.executeAsyncCommando(deployCommando, `npx firebase${debug} deploy --only hosting`, (stdout, stderr, exitCode) => {
|
|
316
|
-
if (exitCode !== 0) {
|
|
317
|
-
throw new CommandoException(`Failed to deploy hosting (exit code ${exitCode})`, stdout, stderr, exitCode);
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
this.logInfo(`Hosting deployed: `, this.hosting);
|
|
321
|
-
// Cleanup temp directory (optional - keep for debugging)
|
|
322
|
-
// await FileSystemUtils.folder.delete(deployTempDir);
|
|
323
|
-
}
|
|
324
62
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { FirebasePackageConfig } from '../../../config/types/package/package.js';
|
|
2
|
+
import { UnitPhaseImplementor } from '../../../core/types.js';
|
|
3
|
+
import { StringMap, TS_Object } from '@nu-art/ts-common';
|
|
4
|
+
import { Phase_BuildPushImage, Phase_Deploy, Phase_DeployImage, Phase_Launch } from '../../../phases/definitions/consts.js';
|
|
5
|
+
import { Unit_TypescriptLib, Unit_TypescriptLib_Config } from '../Unit_TypescriptLib.js';
|
|
6
|
+
export type FirebaseHostingConfig = {
|
|
7
|
+
public: string;
|
|
8
|
+
rewrites: {
|
|
9
|
+
source: string;
|
|
10
|
+
destination: string;
|
|
11
|
+
}[];
|
|
12
|
+
};
|
|
13
|
+
export type FirebaseHosting_EnvConfig = {
|
|
14
|
+
config: TS_Object;
|
|
15
|
+
projectId: string;
|
|
16
|
+
isLocal?: boolean;
|
|
17
|
+
};
|
|
18
|
+
export type Unit_HostingApp_Config = Unit_TypescriptLib_Config & {
|
|
19
|
+
firebaseConfig?: FirebasePackageConfig;
|
|
20
|
+
servingPort: number;
|
|
21
|
+
hostingConfig?: FirebaseHostingConfig;
|
|
22
|
+
envConfig: FirebaseHosting_EnvConfig;
|
|
23
|
+
sources?: string[];
|
|
24
|
+
hostingDeployment?: {
|
|
25
|
+
artifactRegistry: {
|
|
26
|
+
region: string;
|
|
27
|
+
repository: string;
|
|
28
|
+
projectId: string;
|
|
29
|
+
};
|
|
30
|
+
packageName: string;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Abstract base for hosting application units (Firebase Hosting with webpack or Vite).
|
|
35
|
+
* Handles Firebase config resolution, deploy, buildPushImage, deployImage.
|
|
36
|
+
* Subclasses implement compileImpl() and runApp() for the specific bundler.
|
|
37
|
+
*/
|
|
38
|
+
export declare abstract class Unit_HostingApp<C extends Unit_HostingApp_Config = Unit_HostingApp_Config> extends Unit_TypescriptLib<C> implements UnitPhaseImplementor<[Phase_Launch, Phase_Deploy, Phase_BuildPushImage, Phase_DeployImage]> {
|
|
39
|
+
hosting: StringMap;
|
|
40
|
+
injectedMetadata: StringMap;
|
|
41
|
+
static DefaultConfig_Hosting: {
|
|
42
|
+
servingPort: number;
|
|
43
|
+
output: string;
|
|
44
|
+
};
|
|
45
|
+
constructor(config: Unit_HostingApp<C>['config']);
|
|
46
|
+
prepare(): Promise<void>;
|
|
47
|
+
compile(): Promise<void>;
|
|
48
|
+
launch(): Promise<void>;
|
|
49
|
+
deploy(): Promise<void>;
|
|
50
|
+
protected getEnvConfig(): C["envConfig"];
|
|
51
|
+
private resolveHostingRC;
|
|
52
|
+
private resolveHostingJSON;
|
|
53
|
+
private resolveHostingRuntimeConfig;
|
|
54
|
+
protected abstract compileImpl(): Promise<void>;
|
|
55
|
+
protected abstract runApp(): Promise<void>;
|
|
56
|
+
protected createAppVersionFile(): Promise<void>;
|
|
57
|
+
buildPushImage(): Promise<void>;
|
|
58
|
+
deployImage(): Promise<void>;
|
|
59
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { ImplementationMissingException } from '@nu-art/ts-common';
|
|
2
|
+
import { CONST_DeployHostingDir, CONST_DeploymentMetadata, CONST_FirebaseJSON, CONST_FirebaseRC, CONST_HostingBuildTarball, CONST_StagingDir, CONST_TrashDir, CONST_VersionApp } from '../../../config/consts.js';
|
|
3
|
+
import { Commando_NVM, CommandoException } from '@nu-art/commando';
|
|
4
|
+
import { resolve } from 'path';
|
|
5
|
+
import { Unit_TypescriptLib } from '../Unit_TypescriptLib.js';
|
|
6
|
+
import { deployLogFilter, ensureArtifactRegistryRepository } from './common.js';
|
|
7
|
+
import { FileSystemUtils } from '@nu-art/ts-common/utils/FileSystemUtils';
|
|
8
|
+
/**
|
|
9
|
+
* Abstract base for hosting application units (Firebase Hosting with webpack or Vite).
|
|
10
|
+
* Handles Firebase config resolution, deploy, buildPushImage, deployImage.
|
|
11
|
+
* Subclasses implement compileImpl() and runApp() for the specific bundler.
|
|
12
|
+
*/
|
|
13
|
+
export class Unit_HostingApp extends Unit_TypescriptLib {
|
|
14
|
+
hosting = {};
|
|
15
|
+
injectedMetadata = {};
|
|
16
|
+
static DefaultConfig_Hosting = {
|
|
17
|
+
servingPort: 8100,
|
|
18
|
+
output: 'dist',
|
|
19
|
+
};
|
|
20
|
+
constructor(config) {
|
|
21
|
+
super(config);
|
|
22
|
+
this.addToClassStack(Unit_HostingApp);
|
|
23
|
+
}
|
|
24
|
+
//######################### Phase Implementations #########################
|
|
25
|
+
async prepare() {
|
|
26
|
+
await super.prepare();
|
|
27
|
+
await this.resolveHostingRC();
|
|
28
|
+
await this.resolveHostingJSON();
|
|
29
|
+
await this.resolveHostingRuntimeConfig();
|
|
30
|
+
}
|
|
31
|
+
async compile() {
|
|
32
|
+
await this.resolveTSConfig(resolve(this.config.fullPath, './src'), 'main', { compilerOptions: { declaration: false } });
|
|
33
|
+
await this.clearOutputDir();
|
|
34
|
+
await this.createAppVersionFile();
|
|
35
|
+
await this.compileImpl();
|
|
36
|
+
}
|
|
37
|
+
async launch() {
|
|
38
|
+
this.setStatus('Launching');
|
|
39
|
+
await this.releasePorts([`${this.config.servingPort}`]);
|
|
40
|
+
await this.runApp();
|
|
41
|
+
}
|
|
42
|
+
async deploy() {
|
|
43
|
+
const commando = this.allocateCommando(Commando_NVM).applyNVM()
|
|
44
|
+
.cd(this.config.fullPath)
|
|
45
|
+
.setLogLevelFilter(deployLogFilter)
|
|
46
|
+
.onLog(/.*Hosting URL.*(https:\/\/.*?)$/, match => {
|
|
47
|
+
this.hosting[match[1]] = match[2];
|
|
48
|
+
});
|
|
49
|
+
const debug = this.runtimeContext.runtimeParams.verbose ? ' --debug' : '';
|
|
50
|
+
await this.executeAsyncCommando(commando, `${this.npmCommand('firebase')}${debug} deploy --only hosting`);
|
|
51
|
+
}
|
|
52
|
+
//######################### ResolveConfig Logic #########################
|
|
53
|
+
getEnvConfig() {
|
|
54
|
+
const envConfig = this.config.envConfig;
|
|
55
|
+
if (!envConfig)
|
|
56
|
+
throw new ImplementationMissingException(`Missing EnvConfig in unit ${this.config.label}`);
|
|
57
|
+
return envConfig;
|
|
58
|
+
}
|
|
59
|
+
async resolveHostingRC() {
|
|
60
|
+
const envConfig = this.getEnvConfig();
|
|
61
|
+
const rcConfig = { projects: { default: envConfig.projectId } };
|
|
62
|
+
const targetPath = `${this.config.fullPath}/${CONST_FirebaseRC}`;
|
|
63
|
+
await FileSystemUtils.file.write.json(targetPath, rcConfig);
|
|
64
|
+
}
|
|
65
|
+
async resolveHostingJSON() {
|
|
66
|
+
const envConfig = this.getEnvConfig();
|
|
67
|
+
const targetPath = `${this.config.fullPath}/${CONST_FirebaseJSON}`;
|
|
68
|
+
let fileContent;
|
|
69
|
+
if (envConfig.isLocal)
|
|
70
|
+
fileContent = {};
|
|
71
|
+
else
|
|
72
|
+
fileContent = {
|
|
73
|
+
hosting: this.config.hostingConfig ?? {
|
|
74
|
+
'public': 'dist',
|
|
75
|
+
'rewrites': [
|
|
76
|
+
{ 'source': '**', 'destination': '/index.html' }
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
await FileSystemUtils.file.write.json(targetPath, fileContent);
|
|
81
|
+
}
|
|
82
|
+
async resolveHostingRuntimeConfig() {
|
|
83
|
+
const envConfig = this.getEnvConfig().config;
|
|
84
|
+
const targetPath = resolve(this.config.fullPath, `./src/main/config.ts`);
|
|
85
|
+
const fileContent = `export const config = ${JSON.stringify(envConfig, null, 2)};`;
|
|
86
|
+
await FileSystemUtils.file.write(targetPath, fileContent);
|
|
87
|
+
}
|
|
88
|
+
//######################### Shared helpers #########################
|
|
89
|
+
async createAppVersionFile() {
|
|
90
|
+
const targetPath = `${this.config.fullPath}/src/main/${CONST_VersionApp}`;
|
|
91
|
+
const appVersion = this.runtimeContext.version;
|
|
92
|
+
await FileSystemUtils.file.write.json(targetPath, { version: appVersion });
|
|
93
|
+
}
|
|
94
|
+
//######################### Build Push Image Phase #########################
|
|
95
|
+
async buildPushImage() {
|
|
96
|
+
const hostingDeployment = this.config.hostingDeployment;
|
|
97
|
+
if (!hostingDeployment) {
|
|
98
|
+
throw new ImplementationMissingException(`Missing hostingDeployment config in unit ${this.config.key}`);
|
|
99
|
+
}
|
|
100
|
+
const buildTag = this.runtimeContext.runtimeParams.buildPushImage;
|
|
101
|
+
if (!buildTag) {
|
|
102
|
+
throw new ImplementationMissingException(`Missing buildPushImage runtime param in unit ${this.config.key}`);
|
|
103
|
+
}
|
|
104
|
+
const artifactRegistry = hostingDeployment.artifactRegistry;
|
|
105
|
+
const packageName = hostingDeployment.packageName;
|
|
106
|
+
if (!packageName) {
|
|
107
|
+
throw new ImplementationMissingException(`Missing packageName in hostingDeployment config for unit ${this.config.key}`);
|
|
108
|
+
}
|
|
109
|
+
this.logInfo(`Building and uploading hosting package to Artifact Registry:`);
|
|
110
|
+
this.logInfo(` Package: ${packageName}`);
|
|
111
|
+
this.logInfo(` Tag: ${buildTag}`);
|
|
112
|
+
if (this.runtimeContext.runtimeParams.dryRun) {
|
|
113
|
+
this.logInfo(`[DRY RUN] Would build and upload hosting package: ${packageName}:${buildTag}`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const commando = this.allocateCommando();
|
|
117
|
+
await ensureArtifactRegistryRepository(commando, artifactRegistry, 'generic', this);
|
|
118
|
+
const metadata = {
|
|
119
|
+
...this.injectedMetadata,
|
|
120
|
+
'build.timestamp': new Date().toISOString(),
|
|
121
|
+
'build.tag': buildTag,
|
|
122
|
+
'build.project': artifactRegistry.projectId,
|
|
123
|
+
'build.package-name': packageName,
|
|
124
|
+
'version': this.runtimeContext.version,
|
|
125
|
+
'git.commit': process.env.GIT_COMMIT || '',
|
|
126
|
+
'git.branch': process.env.GIT_BRANCH || '',
|
|
127
|
+
'build.user': process.env.USER || '',
|
|
128
|
+
};
|
|
129
|
+
this.logDebug(`Metadata: `, metadata);
|
|
130
|
+
const buildOutputDir = resolve(this.config.fullPath, CONST_TrashDir);
|
|
131
|
+
const stagingDir = resolve(buildOutputDir, CONST_StagingDir);
|
|
132
|
+
await FileSystemUtils.folder.delete(stagingDir);
|
|
133
|
+
await FileSystemUtils.folder.create(stagingDir);
|
|
134
|
+
const tarballPath = resolve(buildOutputDir, CONST_HostingBuildTarball);
|
|
135
|
+
const outputDirName = resolve(this.config.output).split('/').pop() || 'dist';
|
|
136
|
+
await FileSystemUtils.folder.copy(this.config.output, resolve(stagingDir, outputDirName));
|
|
137
|
+
await FileSystemUtils.file.write.json(resolve(stagingDir, CONST_DeploymentMetadata), metadata);
|
|
138
|
+
commando.cd(stagingDir);
|
|
139
|
+
await this.executeAsyncCommando(commando, `tar -czf ${tarballPath} ${CONST_DeploymentMetadata} ${outputDirName}`, (stdout, stderr, exitCode) => {
|
|
140
|
+
if (exitCode !== 0)
|
|
141
|
+
throw new CommandoException(`Failed to create tarball (exit code ${exitCode})`, stdout, stderr, exitCode);
|
|
142
|
+
});
|
|
143
|
+
this.logInfo(`Created tarball: ${tarballPath}`);
|
|
144
|
+
const region = artifactRegistry.region;
|
|
145
|
+
const repository = artifactRegistry.repository;
|
|
146
|
+
const projectId = artifactRegistry.projectId;
|
|
147
|
+
await this.executeAsyncCommando(commando, `gcloud artifacts generic upload --package=${packageName} --version=${buildTag} --source=${tarballPath} --location=${region} --repository=${repository} --project=${projectId}`, (stdout, stderr, exitCode) => {
|
|
148
|
+
if (exitCode !== 0)
|
|
149
|
+
throw new CommandoException(`Failed to upload hosting package to Artifact Registry (exit code ${exitCode})`, stdout, stderr, exitCode);
|
|
150
|
+
});
|
|
151
|
+
this.logInfo(`Successfully uploaded hosting package: ${packageName}:${buildTag} and ${packageName}:latest`);
|
|
152
|
+
}
|
|
153
|
+
//######################### Deploy Image Phase #########################
|
|
154
|
+
async deployImage() {
|
|
155
|
+
const hostingDeployment = this.config.hostingDeployment;
|
|
156
|
+
if (!hostingDeployment) {
|
|
157
|
+
throw new ImplementationMissingException(`Missing hostingDeployment config in unit ${this.config.key}`);
|
|
158
|
+
}
|
|
159
|
+
const deployTag = this.runtimeContext.runtimeParams.deployImage;
|
|
160
|
+
if (!deployTag) {
|
|
161
|
+
throw new ImplementationMissingException(`Missing deployImage runtime param in unit ${this.config.key}. Generic packages require a specific version tag (cannot use 'latest')`);
|
|
162
|
+
}
|
|
163
|
+
const artifactRegistry = hostingDeployment.artifactRegistry;
|
|
164
|
+
const packageName = hostingDeployment.packageName;
|
|
165
|
+
if (!packageName) {
|
|
166
|
+
throw new ImplementationMissingException(`Missing packageName in hostingDeployment config for unit ${this.config.key}`);
|
|
167
|
+
}
|
|
168
|
+
const region = artifactRegistry.region;
|
|
169
|
+
const repository = artifactRegistry.repository;
|
|
170
|
+
const projectId = artifactRegistry.projectId;
|
|
171
|
+
this.logInfo(`Deploying hosting package: ${packageName}:${deployTag}`);
|
|
172
|
+
if (this.runtimeContext.runtimeParams.dryRun) {
|
|
173
|
+
this.logInfo(`[DRY RUN] Would deploy hosting package: ${packageName}:${deployTag}`);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const deployTempDir = resolve(this.config.fullPath, `${CONST_TrashDir}/${CONST_DeployHostingDir}`);
|
|
177
|
+
this.logInfo(`Setting up deployment directory: ${deployTempDir}`);
|
|
178
|
+
await FileSystemUtils.folder.delete(deployTempDir);
|
|
179
|
+
await FileSystemUtils.folder.create(deployTempDir);
|
|
180
|
+
const commando = this.allocateCommando(Commando_NVM)
|
|
181
|
+
.applyNVM()
|
|
182
|
+
.cd(deployTempDir)
|
|
183
|
+
.mark();
|
|
184
|
+
this.logInfo(`Downloading hosting package from Artifact Registry from: ${projectId}/${repository}/${packageName}/${deployTag}`);
|
|
185
|
+
await this.executeAsyncCommando(commando, `gcloud artifacts generic download --package=${packageName} --version=${deployTag} --destination=${deployTempDir} --location=${region} --repository=${repository} --project=${projectId}`, (stdout, stderr, exitCode) => {
|
|
186
|
+
if (exitCode !== 0)
|
|
187
|
+
throw new CommandoException(`Failed to download hosting package from Artifact Registry (exit code ${exitCode})`, stdout, stderr, exitCode);
|
|
188
|
+
});
|
|
189
|
+
this.logInfo(`Locating downloaded tarball...`);
|
|
190
|
+
const downloadedFiles = await FileSystemUtils.folder.list(deployTempDir);
|
|
191
|
+
const tarballFile = downloadedFiles.find(file => file.endsWith('.tar.gz'));
|
|
192
|
+
if (!tarballFile)
|
|
193
|
+
throw new ImplementationMissingException(`Downloaded tarball not found in ${deployTempDir}. Files found: ${downloadedFiles.join(', ')}`);
|
|
194
|
+
const tarballPath = resolve(deployTempDir, tarballFile);
|
|
195
|
+
this.logDebug(`Downloaded tarball: ${tarballPath}`);
|
|
196
|
+
this.logInfo(`Extracting hosting package...`);
|
|
197
|
+
await this.executeAsyncCommando(commando, `tar -xzf ${tarballPath} -C ${deployTempDir}`, (stdout, stderr, exitCode) => {
|
|
198
|
+
if (exitCode !== 0) {
|
|
199
|
+
throw new CommandoException(`Failed to extract tarball (exit code ${exitCode})`, stdout, stderr, exitCode);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
this.logInfo(`Extracted hosting package to: ${deployTempDir}`);
|
|
203
|
+
this.logInfo(`Copying firebase configs..`);
|
|
204
|
+
const firebaseJsonPath = resolve(this.config.fullPath, CONST_FirebaseJSON);
|
|
205
|
+
const firebaseRcPath = resolve(this.config.fullPath, CONST_FirebaseRC);
|
|
206
|
+
await FileSystemUtils.file.copy(firebaseJsonPath, resolve(deployTempDir, CONST_FirebaseJSON));
|
|
207
|
+
await FileSystemUtils.file.copy(firebaseRcPath, resolve(deployTempDir, CONST_FirebaseRC));
|
|
208
|
+
this.logDebug(`Copied firebase configs!`);
|
|
209
|
+
const envConfig = this.getEnvConfig();
|
|
210
|
+
this.logInfo(`Deploying to Firebase Hosting: ${deployTempDir} => ${envConfig.projectId}`);
|
|
211
|
+
const deployCommando = this.allocateCommando(Commando_NVM).applyNVM()
|
|
212
|
+
.cd(deployTempDir)
|
|
213
|
+
.setLogLevelFilter(deployLogFilter)
|
|
214
|
+
.onLog(/.*Hosting URL.*(https:\/\/.*?)$/, match => {
|
|
215
|
+
this.hosting[match[1]] = match[2];
|
|
216
|
+
});
|
|
217
|
+
const debug = this.runtimeContext.runtimeParams.verbose ? ' --debug' : '';
|
|
218
|
+
await this.executeAsyncCommando(deployCommando, `npx firebase${debug} deploy --only hosting`, (stdout, stderr, exitCode) => {
|
|
219
|
+
if (exitCode !== 0) {
|
|
220
|
+
throw new CommandoException(`Failed to deploy hosting (exit code ${exitCode})`, stdout, stderr, exitCode);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
this.logInfo(`Hosting deployed: `, this.hosting);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Unit_HostingApp, Unit_HostingApp_Config } from './Unit_HostingApp.js';
|
|
2
|
+
/**
|
|
3
|
+
* Firebase Hosting application unit (Vite bundler).
|
|
4
|
+
* Extends Unit_HostingApp; implements compile via vite build, launch via vite (dev server).
|
|
5
|
+
*/
|
|
6
|
+
export declare class Unit_ViteHostingApp<C extends Unit_HostingApp_Config = Unit_HostingApp_Config> extends Unit_HostingApp<C> {
|
|
7
|
+
constructor(config: Unit_ViteHostingApp<C>['config']);
|
|
8
|
+
protected compileImpl(): Promise<void>;
|
|
9
|
+
protected runApp(): Promise<void>;
|
|
10
|
+
}
|