Skip to content

Commit bdb7f3d

Browse files
authored
Merge pull request #1846 from embroider-build/handle-vite-query-params
Prevent query-params added by vite to be passed to core logic
2 parents e1142b1 + f580815 commit bdb7f3d

File tree

4 files changed

+93
-17
lines changed

4 files changed

+93
-17
lines changed

packages/shared-internals/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export { AppMeta, AddonMeta, PackageInfo } from './metadata';
2-
export { explicitRelative, extensionsPattern, unrelativize, cleanUrl } from './paths';
2+
export { explicitRelative, extensionsPattern, unrelativize, cleanUrl, getUrlQueryParams } from './paths';
33
export { getOrCreate } from './get-or-create';
44
export { default as Package, V2AddonPackage as AddonPackage, V2AppPackage as AppPackage, V2Package } from './package';
55
export { default as PackageCache } from './package-cache';

packages/shared-internals/src/paths.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,22 @@ export function unrelativize(pkg: Package, specifier: string, fromFile: string)
4444

4545
const postfixRE = /[?#].*$/s;
4646

47+
// this pattern includes URL query params (ex: ?direct)
48+
// but excludes specifiers starting with # (ex: #embroider_compats/components/fancy)
49+
// so when using this pattern, #embroider_compat/fancy would be consider a pathname
50+
// without any params.
51+
const postfixREQueryParams = /[?].*$/s;
52+
4753
// this is the same implementation Vite uses internally to keep its
4854
// cache-busting query params from leaking where they shouldn't.
49-
export function cleanUrl(url: string): string {
50-
return url.replace(postfixRE, '');
55+
// includeHashSign true means #my-specifier is considered part of the pathname
56+
export function cleanUrl(url: string, includeHashSign = false): string {
57+
const regexp = includeHashSign ? postfixREQueryParams : postfixRE;
58+
return url.replace(regexp, '');
59+
}
60+
61+
// includeHashSign true means #my-specifier is considered part of the pathname
62+
export function getUrlQueryParams(url: string, includeHashSign = false): string {
63+
const regexp = includeHashSign ? postfixREQueryParams : postfixRE;
64+
return url.match(regexp)?.[0] ?? '';
5165
}

packages/vite/src/request.ts

+74-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ModuleRequest, Resolution } from '@embroider/core';
2-
import { cleanUrl } from '@embroider/core';
2+
import { cleanUrl, getUrlQueryParams } from '@embroider/core';
33
import type { PluginContext, ResolveIdResult } from 'rollup';
44

55
export const virtualPrefix = 'embroider_virtual:';
@@ -28,7 +28,24 @@ export class RollupModuleRequest implements ModuleRequest {
2828

2929
// strip query params off the importer
3030
let fromFile = cleanUrl(nonVirtual);
31-
return new RollupModuleRequest(context, source, fromFile, custom?.embroider?.meta, false, undefined);
31+
let importerQueryParams = getUrlQueryParams(nonVirtual);
32+
33+
// strip query params off the source but keep track of them
34+
// we use regexp-based methods over a URL object because the
35+
// source can be a relative path.
36+
let cleanSource = cleanUrl(source, true);
37+
let queryParams = getUrlQueryParams(source, true);
38+
39+
return new RollupModuleRequest(
40+
context,
41+
cleanSource,
42+
fromFile,
43+
custom?.embroider?.meta,
44+
false,
45+
undefined,
46+
queryParams,
47+
importerQueryParams
48+
);
3249
}
3350
}
3451

@@ -38,7 +55,9 @@ export class RollupModuleRequest implements ModuleRequest {
3855
readonly fromFile: string,
3956
readonly meta: Record<string, any> | undefined,
4057
readonly isNotFound: boolean,
41-
readonly resolvedTo: Resolution<ResolveIdResult> | undefined
58+
readonly resolvedTo: Resolution<ResolveIdResult> | undefined,
59+
private queryParams: string,
60+
private importerQueryParams: string
4261
) {}
4362

4463
get debugType() {
@@ -49,14 +68,40 @@ export class RollupModuleRequest implements ModuleRequest {
4968
return this.specifier.startsWith(virtualPrefix);
5069
}
5170

71+
private get specifierWithQueryParams(): string {
72+
return `${this.specifier}${this.queryParams}`;
73+
}
74+
75+
private get fromFileWithQueryParams(): string {
76+
return `${this.fromFile}${this.importerQueryParams}`;
77+
}
78+
5279
alias(newSpecifier: string) {
53-
return new RollupModuleRequest(this.context, newSpecifier, this.fromFile, this.meta, false, undefined) as this;
80+
return new RollupModuleRequest(
81+
this.context,
82+
newSpecifier,
83+
this.fromFile,
84+
this.meta,
85+
false,
86+
undefined,
87+
this.queryParams,
88+
this.importerQueryParams
89+
) as this;
5490
}
5591
rehome(newFromFile: string) {
5692
if (this.fromFile === newFromFile) {
5793
return this;
5894
} else {
59-
return new RollupModuleRequest(this.context, this.specifier, newFromFile, this.meta, false, undefined) as this;
95+
return new RollupModuleRequest(
96+
this.context,
97+
this.specifier,
98+
newFromFile,
99+
this.meta,
100+
false,
101+
undefined,
102+
this.queryParams,
103+
this.importerQueryParams
104+
) as this;
60105
}
61106
}
62107
virtualize(filename: string) {
@@ -66,7 +111,9 @@ export class RollupModuleRequest implements ModuleRequest {
66111
this.fromFile,
67112
this.meta,
68113
false,
69-
undefined
114+
undefined,
115+
this.queryParams,
116+
this.importerQueryParams
70117
) as this;
71118
}
72119
withMeta(meta: Record<string, any> | undefined): this {
@@ -76,29 +123,40 @@ export class RollupModuleRequest implements ModuleRequest {
76123
this.fromFile,
77124
meta,
78125
this.isNotFound,
79-
this.resolvedTo
126+
this.resolvedTo,
127+
this.queryParams,
128+
this.importerQueryParams
80129
) as this;
81130
}
82131
notFound(): this {
83-
return new RollupModuleRequest(this.context, this.specifier, this.fromFile, this.meta, true, undefined) as this;
132+
return new RollupModuleRequest(
133+
this.context,
134+
this.specifier,
135+
this.fromFile,
136+
this.meta,
137+
true,
138+
undefined,
139+
this.queryParams,
140+
this.importerQueryParams
141+
) as this;
84142
}
85143
async defaultResolve(): Promise<Resolution<ResolveIdResult>> {
86144
if (this.isVirtual) {
87145
return {
88146
type: 'found',
89147
filename: this.specifier,
90-
result: { id: this.specifier, resolvedBy: this.fromFile },
148+
result: { id: this.specifierWithQueryParams, resolvedBy: this.fromFileWithQueryParams },
91149
isVirtual: this.isVirtual,
92150
};
93151
}
94152
if (this.isNotFound) {
95153
// TODO: we can make sure this looks correct in rollup & vite output when a
96154
// user encounters it
97-
let err = new Error(`module not found ${this.specifier}`);
155+
let err = new Error(`module not found ${this.specifierWithQueryParams}`);
98156
(err as any).code = 'MODULE_NOT_FOUND';
99157
return { type: 'not_found', err };
100158
}
101-
let result = await this.context.resolve(this.specifier, this.fromFile, {
159+
let result = await this.context.resolve(this.specifierWithQueryParams, this.fromFileWithQueryParams, {
102160
skipSelf: true,
103161
custom: {
104162
embroider: {
@@ -108,7 +166,8 @@ export class RollupModuleRequest implements ModuleRequest {
108166
},
109167
});
110168
if (result) {
111-
return { type: 'found', filename: result.id, result, isVirtual: this.isVirtual };
169+
let { pathname } = new URL(result.id, 'http://example.com');
170+
return { type: 'found', filename: pathname, result, isVirtual: this.isVirtual };
112171
} else {
113172
return { type: 'not_found', err: undefined };
114173
}
@@ -121,7 +180,9 @@ export class RollupModuleRequest implements ModuleRequest {
121180
this.fromFile,
122181
this.meta,
123182
this.isNotFound,
124-
resolution
183+
resolution,
184+
this.queryParams,
185+
this.importerQueryParams
125186
) as this;
126187
}
127188
}

packages/vite/src/resolver.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ export function resolver(): Plugin {
5252
},
5353
load(id) {
5454
if (id.startsWith(virtualPrefix)) {
55-
let { src, watches } = virtualContent(id.slice(virtualPrefix.length), resolverLoader.resolver);
55+
let { pathname } = new URL(id, 'http://example.com');
56+
let { src, watches } = virtualContent(pathname.slice(virtualPrefix.length + 1), resolverLoader.resolver);
5657
virtualDeps.set(id, watches);
5758
server?.watcher.add(watches);
5859
return src;

0 commit comments

Comments
 (0)