Skip to content

Commit

Permalink
Merge pull request #2100 from embroider-build/esbuild-fixes
Browse files Browse the repository at this point in the history
Esbuild fixes
  • Loading branch information
ef4 authored Sep 9, 2024
2 parents 99a3649 + a3098ae commit 52687d4
Show file tree
Hide file tree
Showing 18 changed files with 987 additions and 581 deletions.
4 changes: 2 additions & 2 deletions packages/compat/src/audit/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ async function execute(
let stderrBuffer: string[] = [];
let stdoutBuffer: string[] = [];
let combinedBuffer: string[] = [];
child.stderr.on('data', data => {
child.stderr!.on('data', data => {
stderrBuffer.push(data);
combinedBuffer.push(data);
});
child.stdout.on('data', data => {
child.stdout!.on('data', data => {
stdoutBuffer.push(data);
combinedBuffer.push(data);
});
Expand Down
14 changes: 6 additions & 8 deletions packages/compat/src/compat-app-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,12 @@ export class CompatAppBuilder {
}

private resolvableExtensions(): string[] {
// webpack's default is ['.wasm', '.mjs', '.js', '.json']. Keeping that
// subset in that order is sensible, since many third-party libraries will
// expect it to work that way.
//
// For TS, we defer to ember-cli-babel, and the setting for
// "enableTypescriptTransform" can be set with and without
// ember-cli-typescript
return ['.wasm', '.mjs', '.js', '.json', '.ts', '.hbs', '.hbs.js', '.gjs', '.gts'];
let fromEnv = process.env.EMBROIDER_RESOLVABLE_EXTENSIONS;
if (fromEnv) {
return fromEnv.split(',');
} else {
return ['.mjs', '.gjs', '.js', '.mts', '.gts', '.ts', '.hbs', '.hbs.js', '.json'];
}
}

private modulePrefix(): string {
Expand Down
136 changes: 82 additions & 54 deletions packages/core/src/module-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -971,20 +971,13 @@ export class Resolver {
}

let pkg = this.packageCache.ownerOfFile(request.fromFile);
if (!pkg || !pkg.isV2Ember()) {
return request;
}

// real deps take precedence over renaming rules. That is, a package like
// ember-source might provide backburner via module renaming, but if you
// have an explicit dependency on backburner you should still get that real
// copy.

// if (pkg.root === this.options.engines[0].root && request.specifier === `${pkg.name}/environment/config`) {
// return logTransition('legacy config location', request, request.alias(`${pkg.name}/app/environment/config`));
// }

if (!pkg.hasDependency(packageName)) {
if (!pkg?.hasDependency(packageName)) {
for (let [candidate, replacement] of Object.entries(this.options.renameModules)) {
if (candidate === request.specifier) {
return logTransition(`renameModules`, request, request.alias(replacement));
Expand All @@ -1008,6 +1001,10 @@ export class Resolver {
}
}

if (!pkg || !pkg.isV2Ember()) {
return request;
}

if (pkg.name === packageName) {
// we found a self-import
if (pkg.meta['auto-upgraded']) {
Expand Down Expand Up @@ -1285,63 +1282,42 @@ export class Resolver {
}

let pkg = this.packageCache.ownerOfFile(request.fromFile);
if (!pkg) {
return logTransition('no identifiable owningPackage', request);
}

// meta.originalFromFile gets set when we want to try to rehome a request
// but then come back to the original location here in the fallback when the
// rehomed request fails
let movedPkg = this.packageCache.maybeMoved(pkg);
if (movedPkg !== pkg) {
let originalFromFile = request.meta?.originalFromFile;
if (typeof originalFromFile !== 'string') {
throw new Error(`bug: embroider resolver's meta is not propagating`);
}
request = request.rehome(originalFromFile);
pkg = movedPkg;
if (pkg) {
({ pkg, request } = this.restoreRehomedRequest(pkg, request));
}

if (!pkg.isV2Ember()) {
return logTransition('fallbackResolve: not in an ember package', request);
if (!pkg?.isV2Ember()) {
// this request is coming from a file that appears to be owned by no ember
// package. We offer one fallback behavior for such files. They're allowed
// to resolve from the app's namespace.
//
// This makes it possible for integrations like vite to leave references
// to the app in their pre-bundled dependencies, which will end up in an
// arbitrary cache that is not inside any particular package.
let description = pkg ? 'non-ember package' : 'unowned module';

let packageName = getPackageName(request.specifier);
if (packageName === this.options.modulePrefix) {
return logTransition(
`fallbackResolver: ${description} resolved app namespace`,
request,
request.rehome(this.packageCache.maybeMoved(this.packageCache.get(this.options.appRoot)).root)
);
}
return logTransition(`fallbackResolver: ${description}`, request);
}

let packageName = getPackageName(request.specifier);
if (!packageName) {
// this is a relative import

let withinEngine = this.engineConfig(pkg.name);
if (withinEngine) {
// it's a relative import inside an engine (which also means app), which
// means we may need to satisfy the request via app tree merging.

let logicalName = engineRelativeName(pkg, resolve(dirname(request.fromFile), request.specifier));
if (!logicalName) {
return logTransition(
'fallbackResolve: relative failure because this file is not externally accessible',
request
);
}
let appJSMatch = await this.searchAppTree(request, withinEngine, logicalName);
if (appJSMatch) {
return logTransition('fallbackResolve: relative appJsMatch', request, appJSMatch);
} else {
return logTransition('fallbackResolve: relative appJs search failure', request);
}
} else {
// nothing else to do for relative imports
return logTransition('fallbackResolve: relative failure', request);
}
return this.relativeFallbackResolve(pkg, request);
}

// auto-upgraded packages can fall back to the set of known active addons
if (pkg.needsLooseResolving()) {
let addon = this.locateActiveAddon(packageName);
if (addon) {
const rehomed = request.rehome(addon.canResolveFromFile);
if (rehomed !== request) {
return logTransition(`activeAddons`, request, rehomed);
}
let activeAddon = this.maybeFallbackToActiveAddon(request, packageName);
if (activeAddon) {
return activeAddon;
}
}

Expand Down Expand Up @@ -1391,6 +1367,58 @@ export class Resolver {
return logTransition('fallbackResolve final exit', request);
}

private restoreRehomedRequest<R extends ModuleRequest>(pkg: Package, request: R): { pkg: Package; request: R } {
// meta.originalFromFile gets set when we want to try to rehome a request
// but then come back to the original location here in the fallback when the
// rehomed request fails
let movedPkg = this.packageCache.maybeMoved(pkg);
if (movedPkg !== pkg) {
let originalFromFile = request.meta?.originalFromFile;
if (typeof originalFromFile !== 'string') {
throw new Error(`bug: embroider resolver's meta is not propagating`);
}
request = request.rehome(originalFromFile);
pkg = movedPkg;
}
return { pkg, request };
}

private async relativeFallbackResolve<R extends ModuleRequest>(pkg: Package, request: R): Promise<R> {
let withinEngine = this.engineConfig(pkg.name);
if (withinEngine) {
// it's a relative import inside an engine (which also means app), which
// means we may need to satisfy the request via app tree merging.

let logicalName = engineRelativeName(pkg, resolve(dirname(request.fromFile), request.specifier));
if (!logicalName) {
return logTransition(
'fallbackResolve: relative failure because this file is not externally accessible',
request
);
}
let appJSMatch = await this.searchAppTree(request, withinEngine, logicalName);
if (appJSMatch) {
return logTransition('fallbackResolve: relative appJsMatch', request, appJSMatch);
} else {
return logTransition('fallbackResolve: relative appJs search failure', request);
}
} else {
// nothing else to do for relative imports
return logTransition('fallbackResolve: relative failure', request);
}
}

private maybeFallbackToActiveAddon<R extends ModuleRequest>(request: R, requestedPackageName: string): R | undefined {
// auto-upgraded packages can fall back to the set of known active addons
let addon = this.locateActiveAddon(requestedPackageName);
if (addon) {
const rehomed = request.rehome(addon.canResolveFromFile);
if (rehomed !== request) {
return logTransition(`activeAddons`, request, rehomed);
}
}
}

private getEntryFromMergeMap(
inEngineSpecifier: string,
root: string
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/virtual-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,14 +172,14 @@ function decodeVirtualExternalCJSModule(filename: string) {
}

const pairComponentMarker = '-embroider-pair-component';
const pairComponentPattern = /^(?<hbsModule>.*)\/(?<jsModule>[^\/]*)-embroider-pair-component$/;
const pairComponentPattern = /^(?<hbsModule>.*)__vpc__(?<jsModule>[^\/]*)-embroider-pair-component$/;

export function virtualPairComponent(hbsModule: string, jsModule: string | undefined): string {
let relativeJSModule = '';
if (jsModule) {
relativeJSModule = explicitRelative(hbsModule, jsModule);
relativeJSModule = explicitRelative(dirname(hbsModule), jsModule);
}
return `${hbsModule}/${encodeURIComponent(relativeJSModule)}${pairComponentMarker}`;
return `${hbsModule}__vpc__${encodeURIComponent(relativeJSModule)}${pairComponentMarker}`;
}

function decodeVirtualPairComponent(
Expand Down
1 change: 1 addition & 0 deletions packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"dependencies": {
"@babel/core": "^7.22.9",
"@embroider/macros": "workspace:*",
"@embroider/reverse-exports": "workspace:*",
"@rollup/pluginutils": "^4.1.1",
"assert-never": "^1.2.1",
"content-tag": "^2.0.1",
Expand Down
29 changes: 16 additions & 13 deletions packages/vite/src/build.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
import { fork } from 'child_process';
import type { Plugin } from 'vite';

export function emberBuild(command: string, mode: string): Promise<void> {
export function emberBuild(command: string, mode: string, resolvableExtensions: string[] | undefined): Promise<void> {
let env: Record<string, string> = {
...process.env,
EMBROIDER_PREBUILD: 'true',
};

if (resolvableExtensions) {
env['EMBROIDER_RESOLVABLE_EXTENSIONS'] = resolvableExtensions?.join(',');
}

if (command === 'build') {
return new Promise((resolve, reject) => {
const child = fork('./node_modules/ember-cli/bin/ember', ['build', '--environment', mode], {
env: {
...process.env,
EMBROIDER_PREBUILD: 'true',
},
});
const child = fork('./node_modules/ember-cli/bin/ember', ['build', '--environment', mode], { env });
child.on('exit', code => (code === 0 ? resolve() : reject()));
});
}
return new Promise((resolve, reject) => {
const child = fork('./node_modules/ember-cli/bin/ember', ['build', '--watch', '--environment', mode], {
silent: true,
env: {
...process.env,
EMBROIDER_PREBUILD: 'true',
},
env,
});
child.on('exit', code => (code === 0 ? resolve() : reject(new Error('ember build --watch failed'))));
child.on('spawn', () => {
Expand All @@ -39,13 +40,15 @@ export function emberBuild(command: string, mode: string): Promise<void> {
export function compatPrebuild(): Plugin {
let viteCommand: string | undefined;
let viteMode: string | undefined;
let resolvableExtensions: string[] | undefined;

return {
name: 'embroider-builder',
enforce: 'pre',
config(_config, { mode, command }) {
config(config, { mode, command }) {
viteCommand = command;
viteMode = mode;
resolvableExtensions = config.resolve?.extensions;
},
async buildStart() {
if (!viteCommand) {
Expand All @@ -54,7 +57,7 @@ export function compatPrebuild(): Plugin {
if (!viteMode) {
throw new Error(`bug: embroider compatPrebuild did not detect Vite's mode`);
}
await emberBuild(viteCommand, viteMode);
await emberBuild(viteCommand, viteMode, resolvableExtensions);
},
};
}
Loading

0 comments on commit 52687d4

Please sign in to comment.