Skip to content

Commit 6eaf24a

Browse files
Vite and NPM workspace fixes (#5640)
* Better error message if a framework isn't detected * Handle NPM workspaces for both Vite and Angular * Error if the node_module binary isn't found * Force vite build to production mode ------ Co-authored-by: Tatsuya Yamamoto <TatsuyaYamamoto@users.noreply.github.com>
1 parent 63c9bd8 commit 6eaf24a

File tree

6 files changed

+60
-24
lines changed

6 files changed

+60
-24
lines changed

.eslintrc.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,5 +125,7 @@ module.exports = {
125125
"scripts/webframeworks-deploy-tests/hosting/**",
126126
"scripts/frameworks-tests/vite-project/**",
127127
"/src/frameworks/docs/**",
128+
// This file is taking a very long time to lint, 2-4m
129+
"src/emulator/auth/schema.ts",
128130
],
129131
};

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
- Fix bug where functions shell failed to invoke event triggered functions in debug mode. (#5609)
22
- Fixed bug with the web frameworks proxy that could see unexpected 404 errors while emulating. (#5525)
33
- Added experimental support for SvelteKit codebases. (#5525)
4+
- Allow usage of Angular and Vite within an NPM workspace. (#5640)
5+
- Force Vite to build the production bundle when deploying to Hosting. (#5640)
46
- Fix bug where eagerly initializing UA failed function deployment that imported firebase-tools as a library. (#5666)

src/frameworks/angular/index.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
Discovery,
1111
findDependency,
1212
FrameworkType,
13+
getNodeModuleBin,
1314
relativeRequire,
1415
SupportLevel,
1516
} from "..";
@@ -20,7 +21,6 @@ export const name = "Angular";
2021
export const support = SupportLevel.Experimental;
2122
export const type = FrameworkType.Framework;
2223

23-
const CLI_COMMAND = join("node_modules", ".bin", process.platform === "win32" ? "ng.cmd" : "ng");
2424
const DEFAULT_BUILD_SCRIPT = ["ng build"];
2525

2626
export async function discover(dir: string): Promise<Discovery | undefined> {
@@ -70,7 +70,8 @@ export async function build(dir: string): Promise<BuildResult> {
7070
if (prerenderTarget) {
7171
// TODO there is a bug here. Spawn for now.
7272
// await scheduleTarget(prerenderTarget);
73-
execSync(`${CLI_COMMAND} run ${targetStringFromTarget(prerenderTarget)}`, {
73+
const cli = getNodeModuleBin("ng", dir);
74+
execSync(`${cli} run ${targetStringFromTarget(prerenderTarget)}`, {
7475
cwd: dir,
7576
stdio: "inherit",
7677
});
@@ -91,11 +92,10 @@ export async function getDevModeHandle(dir: string) {
9192
const host = new Promise<string>((resolve) => {
9293
// Can't use scheduleTarget since that—like prerender—is failing on an ESM bug
9394
// will just grep for the hostname
94-
const serve = spawn(
95-
CLI_COMMAND,
96-
["run", targetStringFromTarget(serveTarget), "--host", "localhost"],
97-
{ cwd: dir }
98-
);
95+
const cli = getNodeModuleBin("ng", dir);
96+
const serve = spawn(cli, ["run", targetStringFromTarget(serveTarget), "--host", "localhost"], {
97+
cwd: dir,
98+
});
9999
serve.stdout.on("data", (data: any) => {
100100
process.stdout.write(data);
101101
const match = data.toString().match(/(http:\/\/localhost:\d+)/);

src/frameworks/index.ts

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { HostingRewrites } from "../firebaseConfig";
2828
import * as experiments from "../experiments";
2929
import { ensureTargeted } from "../functions/ensureTargeted";
3030
import { implicitInit } from "../hosting/implicitInit";
31+
import { fileExistsSync } from "../fsutils";
3132

3233
// Use "true &&"" to keep typescript from compiling this file and rewriting
3334
// the import statement into a require
@@ -124,8 +125,6 @@ const DEFAULT_FIND_DEP_OPTIONS: FindDepOptions = {
124125
omitDev: true,
125126
};
126127

127-
const NPM_COMMAND = process.platform === "win32" ? "npm.cmd" : "npm";
128-
129128
export const WebFrameworks: Record<string, Framework> = Object.fromEntries(
130129
readdirSync(__dirname)
131130
.filter((path) => statSync(join(__dirname, path)).isDirectory())
@@ -233,15 +232,30 @@ function scanDependencyTree(searchingFor: string, dependencies = {}): any {
233232
return;
234233
}
235234

235+
export function getNodeModuleBin(name: string, cwd: string) {
236+
const cantFindExecutable = new FirebaseError(`Could not find the ${name} executable.`);
237+
const npmBin = spawnSync("npm", ["bin"], { cwd }).stdout?.toString().trim();
238+
if (!npmBin) {
239+
throw cantFindExecutable;
240+
}
241+
const path = join(npmBin, name);
242+
if (!fileExistsSync(path)) {
243+
throw cantFindExecutable;
244+
}
245+
return path;
246+
}
247+
236248
/**
237249
*
238250
*/
239251
export function findDependency(name: string, options: Partial<FindDepOptions> = {}) {
240-
const { cwd, depth, omitDev } = { ...DEFAULT_FIND_DEP_OPTIONS, ...options };
252+
const { cwd: dir, depth, omitDev } = { ...DEFAULT_FIND_DEP_OPTIONS, ...options };
253+
const cwd = spawnSync("npm", ["root"], { cwd: dir }).stdout?.toString().trim();
254+
if (!cwd) return;
241255
const env: any = Object.assign({}, process.env);
242256
delete env.NODE_ENV;
243257
const result = spawnSync(
244-
NPM_COMMAND,
258+
"npm",
245259
[
246260
"list",
247261
name,
@@ -395,7 +409,10 @@ export async function prepareFrameworks(
395409
process.env.__FIREBASE_DEFAULTS__ = JSON.stringify(firebaseDefaults);
396410
}
397411
const results = await discover(getProjectPath());
398-
if (!results) throw new Error("Epic fail.");
412+
if (!results)
413+
throw new FirebaseError(
414+
"Unable to detect the web framework in use, check firebase-debug.log for more info."
415+
);
399416
const { framework, mayWantBackend, publicDirectory } = results;
400417
const {
401418
build,
@@ -569,7 +586,7 @@ ${firebaseDefaults ? `__FIREBASE_DEFAULTS__=${JSON.stringify(firebaseDefaults)}\
569586

570587
await Promise.all(envs.map((path) => copyFile(path, join(functionsDist, basename(path)))));
571588

572-
execSync(`${NPM_COMMAND} i --omit dev --no-audit`, {
589+
execSync(`npm i --omit dev --no-audit`, {
573590
cwd: functionsDist,
574591
stdio: "inherit",
575592
});

src/frameworks/vite/index.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,14 @@ import { spawn } from "cross-spawn";
33
import { existsSync } from "fs";
44
import { copy, pathExists } from "fs-extra";
55
import { join } from "path";
6-
import { findDependency, FrameworkType, relativeRequire, SupportLevel } from "..";
6+
import { findDependency, FrameworkType, getNodeModuleBin, relativeRequire, SupportLevel } from "..";
77
import { promptOnce } from "../../prompt";
88
import { simpleProxy, warnIfCustomBuildScript } from "../utils";
99

1010
export const name = "Vite";
1111
export const support = SupportLevel.Experimental;
1212
export const type = FrameworkType.Toolchain;
1313

14-
const CLI_COMMAND = join(
15-
"node_modules",
16-
".bin",
17-
process.platform === "win32" ? "vite.cmd" : "vite"
18-
);
19-
2014
export const DEFAULT_BUILD_SCRIPT = ["vite build", "tsc && vite build"];
2115

2216
export const initViteTemplate = (template: string) => async (setup: any, config: any) =>
@@ -67,10 +61,11 @@ export async function build(root: string) {
6761
const { build } = relativeRequire(root, "vite");
6862

6963
await warnIfCustomBuildScript(root, name, DEFAULT_BUILD_SCRIPT);
64+
7065
// SvelteKit uses process.cwd() unfortunately, chdir
7166
const cwd = process.cwd();
7267
process.chdir(root);
73-
await build({ root });
68+
await build({ root, mode: "production" });
7469
process.chdir(cwd);
7570
}
7671

@@ -84,7 +79,8 @@ export async function getDevModeHandle(dir: string) {
8479
const host = new Promise<string>((resolve) => {
8580
// Can't use scheduleTarget since that—like prerender—is failing on an ESM bug
8681
// will just grep for the hostname
87-
const serve = spawn(CLI_COMMAND, [], { cwd: dir });
82+
const cli = getNodeModuleBin("vite", dir);
83+
const serve = spawn(cli, [], { cwd: dir });
8884
serve.stdout.on("data", (data: any) => {
8985
process.stdout.write(data);
9086
const match = data.toString().match(/(http:\/\/.+:\d+)/);

src/test/frameworks/utils.spec.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,30 @@
11
import { expect } from "chai";
22
import * as sinon from "sinon";
33
import * as fs from "fs";
4+
import { resolve, join } from "path";
45

5-
import { warnIfCustomBuildScript } from "../../frameworks/utils";
6-
import { isUrl } from "../../frameworks/utils";
6+
import { warnIfCustomBuildScript, isUrl } from "../../frameworks/utils";
7+
import { getNodeModuleBin } from "../../frameworks";
78

89
describe("Frameworks utils", () => {
10+
describe("getNodeModuleBin", () => {
11+
it("should return expected tsc path", () => {
12+
expect(getNodeModuleBin("tsc", __dirname)).to.equal(
13+
resolve(join(__dirname, "..", "..", "..", "node_modules", ".bin", "tsc"))
14+
);
15+
});
16+
it("should throw when npm root not found", () => {
17+
expect(() => {
18+
getNodeModuleBin("tsc", "/");
19+
}).to.throw("Could not find the tsc executable.");
20+
});
21+
it("should throw when executable not found", () => {
22+
expect(() => {
23+
getNodeModuleBin("xxxxx", __dirname);
24+
}).to.throw("Could not find the xxxxx executable.");
25+
});
26+
});
27+
928
describe("isUrl", () => {
1029
it("should identify http URL", () => {
1130
expect(isUrl("http://firebase.google.com")).to.be.true;

0 commit comments

Comments
 (0)