Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dynamically import Vite #6660

Merged
merged 15 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/frameworks/angular/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,19 @@

export const supportedRange = "14 - 17";

export async function discover(dir: string): Promise<Discovery | undefined> {

Check warning on line 41 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing JSDoc comment
if (!(await pathExists(join(dir, "package.json")))) return;
if (!(await pathExists(join(dir, "angular.json")))) return;
const version = getAngularVersion(dir);
return { mayWantBackend: true, version };
}

export function init(setup: any, config: any) {

Check warning on line 48 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function

Check warning on line 48 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing JSDoc comment

Check warning on line 48 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type

Check warning on line 48 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type
execSync(
`npx --yes -p @angular/cli@"${supportedRange}" ng new ${setup.projectId} --directory ${setup.hosting.source} --skip-git`,

Check warning on line 50 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Invalid type "any" of template literal expression

Check warning on line 50 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe member access .projectId on an `any` value

Check warning on line 50 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Invalid type "any" of template literal expression

Check warning on line 50 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe member access .hosting on an `any` value
{
stdio: "inherit",
cwd: config.projectDir,

Check warning on line 53 in src/frameworks/angular/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe assignment of an `any` value
}
);
return Promise.resolve();
Expand Down Expand Up @@ -90,7 +90,7 @@
}

export async function getDevModeHandle(dir: string, configuration: string) {
const { targetStringFromTarget } = relativeRequire(dir, "@angular-devkit/architect");
const { targetStringFromTarget } = await relativeRequire(dir, "@angular-devkit/architect");
const { serveTarget } = await getContext(dir, configuration);
if (!serveTarget) throw new Error("Could not find the serveTarget");
const host = new Promise<string>((resolve, reject) => {
Expand Down
37 changes: 20 additions & 17 deletions src/frameworks/angular/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ async function localesForTarget(
target: Target,
workspaceProject: ProjectDefinition
) {
const { targetStringFromTarget } = relativeRequire(dir, "@angular-devkit/architect");
const { targetStringFromTarget } = await relativeRequire(dir, "@angular-devkit/architect");
const targetOptions = await architectHost.getOptionsForTarget(target);
if (!targetOptions) {
const targetString = targetStringFromTarget(target);
Expand Down Expand Up @@ -98,10 +98,11 @@ function getValidBuilders(purpose: BUILD_TARGET_PURPOSE): string[] {

export async function getAllTargets(purpose: BUILD_TARGET_PURPOSE, dir: string) {
const validBuilders = getValidBuilders(purpose);
const { NodeJsAsyncHost } = relativeRequire(dir, "@angular-devkit/core/node");
const { workspaces } = relativeRequire(dir, "@angular-devkit/core");
const { targetStringFromTarget } = relativeRequire(dir, "@angular-devkit/architect");

const [{ NodeJsAsyncHost }, { workspaces }, { targetStringFromTarget }] = await Promise.all([
relativeRequire(dir, "@angular-devkit/core/node"),
relativeRequire(dir, "@angular-devkit/core"),
relativeRequire(dir, "@angular-devkit/architect"),
]);
const host = workspaces.createWorkspaceHost(new NodeJsAsyncHost());
const { workspace } = await workspaces.readWorkspace(dir, host);

Expand All @@ -123,17 +124,19 @@ export async function getAllTargets(purpose: BUILD_TARGET_PURPOSE, dir: string)

// TODO(jamesdaniels) memoize, dry up
export async function getContext(dir: string, targetOrConfiguration?: string) {
const { NodeJsAsyncHost } = relativeRequire(dir, "@angular-devkit/core/node");
const { workspaces } = relativeRequire(dir, "@angular-devkit/core");
const { WorkspaceNodeModulesArchitectHost } = relativeRequire(
dir,
"@angular-devkit/architect/node"
);
const { Architect, targetFromTargetString, targetStringFromTarget } = relativeRequire(
dir,
"@angular-devkit/architect"
);
const { parse } = relativeRequire(dir, "jsonc-parser");
const [
{ NodeJsAsyncHost },
{ workspaces },
{ WorkspaceNodeModulesArchitectHost },
{ Architect, targetFromTargetString, targetStringFromTarget },
{ parse },
] = await Promise.all([
relativeRequire(dir, "@angular-devkit/core/node"),
relativeRequire(dir, "@angular-devkit/core"),
relativeRequire(dir, "@angular-devkit/architect/node"),
relativeRequire(dir, "@angular-devkit/architect"),
relativeRequire(dir, "jsonc-parser"),
]);

const host = workspaces.createWorkspaceHost(new NodeJsAsyncHost());
const { workspace } = await workspaces.readWorkspace(dir, host);
Expand Down Expand Up @@ -503,7 +506,7 @@ export async function getServerConfig(sourceDir: string, configuration: string)
}

export async function getBuildConfig(sourceDir: string, configuration: string) {
const { targetStringFromTarget } = relativeRequire(sourceDir, "@angular-devkit/architect");
const { targetStringFromTarget } = await relativeRequire(sourceDir, "@angular-devkit/architect");
const {
buildTarget,
browserTarget,
Expand Down
6 changes: 6 additions & 0 deletions src/frameworks/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,9 @@ export interface FirebaseDefaults {
emulatorHosts?: Record<string, string>;
_authTokenSyncURL?: string;
}

// Only the fields being used are defined here
export interface PackageJson {
main: string;
type?: "commonjs" | "module";
}
8 changes: 5 additions & 3 deletions src/frameworks/next/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ export async function getDevModeHandle(dir: string, _: string, hostingEmulatorIn
}
}

let next = relativeRequire(dir, "next");
let next = await relativeRequire(dir, "next");
if ("default" in next) next = next.default;
const nextApp = next({
dev: true,
Expand All @@ -651,8 +651,10 @@ async function getConfig(
const version = getNextVersion(dir);
if (!version) throw new Error("Unable to find the next dep, try NPM installing?");
if (gte(version, "12.0.0")) {
const { default: loadConfig } = relativeRequire(dir, "next/dist/server/config");
const { PHASE_PRODUCTION_BUILD } = relativeRequire(dir, "next/constants");
const [{ default: loadConfig }, { PHASE_PRODUCTION_BUILD }] = await Promise.all([
relativeRequire(dir, "next/dist/server/config"),
relativeRequire(dir, "next/constants"),
]);
config = await loadConfig(PHASE_PRODUCTION_BUILD, dir);
} else {
try {
Expand Down
49 changes: 35 additions & 14 deletions src/frameworks/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { readJSON as originalReadJSON } from "fs-extra";
import type { ReadOptions } from "fs-extra";
import { extname, join, relative } from "path";
import { dirname, extname, join, relative } from "path";
import { readFile } from "fs/promises";
import { IncomingMessage, request as httpRequest, ServerResponse, Agent } from "http";
import { sync as spawnSync } from "cross-spawn";
Expand All @@ -19,7 +19,7 @@ import {
NPM_COMMAND_TIMEOUT_MILLIES,
VALID_LOCALE_FORMATS,
} from "./constants";
import { BUILD_TARGET_PURPOSE, RequestHandler } from "./interfaces";
import { BUILD_TARGET_PURPOSE, PackageJson, RequestHandler } from "./interfaces";

// Use "true &&"" to keep typescript from compiling this file and rewriting
// the import statement into a require
Expand All @@ -37,6 +37,8 @@ export function isUrl(url: string): boolean {

/**
* add type to readJSON
*
* Note: `throws: false` won't work with the async function: https://github.com/jprichardson/node-fs-extra/issues/542
*/
export function readJSON<JsonType = any>(
file: string,
Expand Down Expand Up @@ -290,37 +292,40 @@ export function findDependency(name: string, options: Partial<FindDepOptions> =
export function relativeRequire(
dir: string,
mod: "@angular-devkit/core"
): typeof import("@angular-devkit/core");
): Promise<typeof import("@angular-devkit/core")>;
export function relativeRequire(
dir: string,
mod: "@angular-devkit/core/node"
): typeof import("@angular-devkit/core/node");
): Promise<typeof import("@angular-devkit/core/node")>;
export function relativeRequire(
dir: string,
mod: "@angular-devkit/architect"
): typeof import("@angular-devkit/architect");
): Promise<typeof import("@angular-devkit/architect")>;
export function relativeRequire(
dir: string,
mod: "@angular-devkit/architect/node"
): typeof import("@angular-devkit/architect/node");
): Promise<typeof import("@angular-devkit/architect/node")>;
export function relativeRequire(
dir: string,
mod: "next/dist/build"
): typeof import("next/dist/build");
): Promise<typeof import("next/dist/build")>;
export function relativeRequire(
dir: string,
mod: "next/dist/server/config"
): typeof import("next/dist/server/config");
): Promise<typeof import("next/dist/server/config")>;
export function relativeRequire(
dir: string,
mod: "next/constants"
): typeof import("next/constants");
): Promise<typeof import("next/constants")>;
export function relativeRequire(
dir: string,
mod: "next"
): typeof import("next") | typeof import("next")["default"];
export function relativeRequire(dir: string, mod: "vite"): typeof import("vite");
export function relativeRequire(dir: string, mod: "jsonc-parser"): typeof import("jsonc-parser");
): Promise<typeof import("next") | typeof import("next")["default"]>;
export function relativeRequire(dir: string, mod: "vite"): Promise<typeof import("vite")>;
export function relativeRequire(
dir: string,
mod: "jsonc-parser"
): Promise<typeof import("jsonc-parser")>;

// TODO the types for @nuxt/kit are causing a lot of troubles, need to do something other than any
// Nuxt 2
Expand All @@ -331,7 +336,7 @@ export function relativeRequire(dir: string, mod: "@nuxt/kit"): Promise<any>;
/**
*
*/
export function relativeRequire(dir: string, mod: string) {
export async function relativeRequire(dir: string, mod: string) {
try {
// If being compiled with webpack, use non webpack require for these calls.
// (VSCode plugin uses webpack which by default replaces require calls
Expand All @@ -345,7 +350,23 @@ export function relativeRequire(dir: string, mod: string) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore prevent VSCE webpack from erroring on non_webpack_require
const path = requireFunc.resolve(mod, { paths: [dir] });
if (extname(path) === ".mjs") {

let packageJson: PackageJson | undefined;
let isEsm = extname(path) === ".mjs";
if (!isEsm) {
packageJson = await readJSON<PackageJson | undefined>(
join(dirname(path), "package.json")
).catch(() => undefined);

isEsm = packageJson?.type === "module";
}

if (isEsm) {
// in case path resolves to a cjs file, use main from package.json
if (extname(path) === ".cjs" && packageJson?.main) {
return dynamicImport(join(dirname(path), packageJson.main));
}

return dynamicImport(pathToFileURL(path).toString());
} else {
return requireFunc(path);
Expand Down
4 changes: 2 additions & 2 deletions src/frameworks/vite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export async function discover(dir: string, plugin?: string, npmDependency?: str
}

export async function build(root: string, target: string) {
const { build } = relativeRequire(root, "vite");
const { build } = await relativeRequire(root, "vite");

await warnIfCustomBuildScript(root, name, DEFAULT_BUILD_SCRIPT);

Expand Down Expand Up @@ -129,7 +129,7 @@ export async function getDevModeHandle(dir: string) {
}

async function getConfig(root: string) {
const { resolveConfig } = relativeRequire(root, "vite");
const { resolveConfig } = await relativeRequire(root, "vite");
// SvelteKit uses process.cwd() unfortunately, we should be defensive here
const cwd = process.cwd();
process.chdir(root);
Expand Down