Skip to content

Commit b120b36

Browse files
authored
fix: resolve route module imports back to virtual (#6098)
1 parent 0f0f025 commit b120b36

File tree

4 files changed

+344
-163
lines changed

4 files changed

+344
-163
lines changed

integration/shared-route-imports-test.ts

Lines changed: 173 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -7,54 +7,181 @@ import { createAppFixture, createFixture, js } from "./helpers/create-fixture";
77
let fixture: Fixture;
88
let appFixture: AppFixture;
99

10-
test.beforeAll(async () => {
11-
fixture = await createFixture({
12-
future: { v2_routeConvention: true },
13-
files: {
14-
"app/routes/parent.jsx": js`
15-
import { createContext, useContext } from "react";
16-
import { Outlet } from "@remix-run/react";
17-
18-
const ParentContext = createContext("❌");
19-
20-
export function useParentContext() {
21-
return useContext(ParentContext);
22-
}
23-
24-
export default function Index() {
25-
return (
26-
<ParentContext.Provider value="✅">
27-
<Outlet />
28-
</ParentContext.Provider>
29-
)
30-
}
31-
`,
32-
33-
"app/routes/parent.child.jsx": js`
34-
import { useParentContext } from "./parent";
35-
36-
export default function Index() {
37-
return <p>{useParentContext()}</p>;
38-
}
39-
`,
40-
},
41-
});
42-
43-
appFixture = await createAppFixture(fixture);
44-
});
10+
test.describe("v1 compiler", () => {
11+
test.beforeAll(async () => {
12+
fixture = await createFixture({
13+
future: { v2_routeConvention: true },
14+
files: {
15+
"app/routes/parent.jsx": js`
16+
import { createContext, useContext } from "react";
17+
import { Outlet } from "@remix-run/react";
18+
19+
const ParentContext = createContext("❌");
20+
21+
export function useParentContext() {
22+
return useContext(ParentContext);
23+
}
24+
25+
export default function Index() {
26+
return (
27+
<ParentContext.Provider value="✅">
28+
<Outlet />
29+
</ParentContext.Provider>
30+
)
31+
}
32+
`,
4533

46-
test.afterAll(() => {
47-
appFixture.close();
48-
});
34+
"app/routes/parent.child.jsx": js`
35+
import { useParentContext } from "./parent";
36+
37+
export default function Index() {
38+
return <p>{useParentContext()}</p>;
39+
}
40+
`,
41+
42+
"app/routes/markdown-parent.mdx": `import { createContext, useContext } from 'react';
43+
import { Outlet } from '@remix-run/react';
44+
45+
export const ParentContext = createContext("❌");
46+
47+
export function useParentContext() {
48+
return useContext(ParentContext);
49+
}
50+
51+
export function ParentProvider() {
52+
return (
53+
<ParentContext.Provider value="✅">
54+
<Outlet />
55+
</ParentContext.Provider>
56+
);
57+
}
58+
59+
<ParentProvider />
60+
`,
61+
"app/routes/markdown-parent.child.mdx": `import { useParentContext } from "./markdown-parent.mdx";
62+
63+
export function UseParentContext() {
64+
return <p>{useParentContext()}</p>;
65+
}
66+
67+
<UseParentContext />
68+
`,
69+
},
70+
});
4971

50-
test("[description of what you expect it to do]", async ({ page }) => {
51-
let app = new PlaywrightFixture(appFixture, page);
52-
// If you need to test interactivity use the `app`
53-
await app.goto("/parent/child", true);
72+
appFixture = await createAppFixture(fixture);
73+
});
74+
75+
test.afterAll(() => {
76+
appFixture.close();
77+
});
5478

55-
await page.waitForSelector("p:has-text('✅')");
79+
test("should render context value from context provider", async ({
80+
page,
81+
}) => {
82+
let app = new PlaywrightFixture(appFixture, page);
83+
await app.goto("/parent/child", true);
84+
85+
await page.waitForSelector("p:has-text('✅')");
86+
});
87+
88+
test("should render context value from context provider exported from mdx", async ({
89+
page,
90+
}) => {
91+
let app = new PlaywrightFixture(appFixture, page);
92+
await app.goto("/markdown-parent/child", true);
93+
94+
await page.waitForSelector("p:has-text('✅')");
95+
});
5696
});
5797

58-
////////////////////////////////////////////////////////////////////////////////
59-
// 💿 Finally, push your changes to your fork of Remix and open a pull request!
60-
////////////////////////////////////////////////////////////////////////////////
98+
test.describe("v2 compiler", () => {
99+
test.beforeAll(async () => {
100+
fixture = await createFixture({
101+
future: { v2_routeConvention: true, unstable_dev: true },
102+
files: {
103+
"app/routes/parent.jsx": js`
104+
import { createContext, useContext } from "react";
105+
import { Outlet } from "@remix-run/react";
106+
107+
const ParentContext = createContext("❌");
108+
109+
export function useParentContext() {
110+
return useContext(ParentContext);
111+
}
112+
113+
export default function Index() {
114+
return (
115+
<ParentContext.Provider value="✅">
116+
<Outlet />
117+
</ParentContext.Provider>
118+
)
119+
}
120+
`,
121+
122+
"app/routes/parent.child.jsx": js`
123+
import { useParentContext } from "./parent";
124+
125+
export default function Index() {
126+
return <p>{useParentContext()}</p>;
127+
}
128+
`,
129+
130+
"app/routes/markdown-parent.mdx": `import { createContext, useContext } from 'react';
131+
import { Outlet } from '@remix-run/react';
132+
133+
export const ParentContext = createContext("❌");
134+
135+
export function useParentContext() {
136+
return useContext(ParentContext);
137+
}
138+
139+
export function ParentProvider() {
140+
return (
141+
<ParentContext.Provider value="✅">
142+
<Outlet />
143+
</ParentContext.Provider>
144+
);
145+
}
146+
147+
<ParentProvider />
148+
`,
149+
"app/routes/markdown-parent.child.mdx": `import { useParentContext } from "./markdown-parent.mdx";
150+
151+
export function UseParentContext() {
152+
const value = useParentContext();
153+
return (
154+
<p>{value}</p>
155+
);
156+
}
157+
158+
<UseParentContext />
159+
`,
160+
},
161+
});
162+
163+
appFixture = await createAppFixture(fixture);
164+
});
165+
166+
test.afterAll(() => {
167+
appFixture.close();
168+
});
169+
170+
test("should render context value from context provider", async ({
171+
page,
172+
}) => {
173+
let app = new PlaywrightFixture(appFixture, page);
174+
await app.goto("/parent/child", true);
175+
176+
await page.waitForSelector("p:has-text('✅')");
177+
});
178+
179+
test("should render context value from context provider exported from mdx", async ({
180+
page,
181+
}) => {
182+
let app = new PlaywrightFixture(appFixture, page);
183+
await app.goto("/markdown-parent/child", true);
184+
185+
await page.waitForSelector("p:has-text('✅')");
186+
});
187+
});

packages/remix-dev/compiler/assets/js.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,29 @@ const createEsbuildConfig = (
7878
"entry.client": ctx.config.entryClientFilePath,
7979
};
8080

81+
let routeModulePaths = new Map<string, string>();
8182
for (let id of Object.keys(ctx.config.routes)) {
82-
// All route entry points are virtual modules that will be loaded by the
83-
// browserEntryPointsPlugin. This allows us to tree-shake server-only code
84-
// that we don't want to run in the browser (i.e. action & loader).
85-
entryPoints[id] = ctx.config.routes[id].file + "?browser";
83+
entryPoints[id] = ctx.config.routes[id].file;
84+
if (ctx.config.future.unstable_dev) {
85+
// In V2 we are doing AST transforms to remove server code, this means we
86+
// have to re-map all route modules back to the same module in the graph
87+
// otherwise we will have duplicate modules in the graph. We have to resolve
88+
// the path as we get the relative for the entrypoint and absolute for imports
89+
// from other modules.
90+
routeModulePaths.set(
91+
ctx.config.routes[id].file,
92+
ctx.config.routes[id].file
93+
);
94+
routeModulePaths.set(
95+
path.resolve(ctx.config.appDirectory, ctx.config.routes[id].file),
96+
ctx.config.routes[id].file
97+
);
98+
} else {
99+
// All route entry points are virtual modules that will be loaded by the
100+
// browserEntryPointsPlugin. This allows us to tree-shake server-only code
101+
// that we don't want to run in the browser (i.e. action & loader).
102+
entryPoints[id] += "?browser";
103+
}
86104
}
87105

88106
let matchPath = ctx.config.tsconfigPath
@@ -105,10 +123,10 @@ const createEsbuildConfig = (
105123
cssFilePlugin(ctx),
106124
absoluteCssUrlsPlugin(),
107125
externalPlugin(/^https?:\/\//, { sideEffects: false }),
108-
mdxPlugin(ctx),
109126
ctx.config.future.unstable_dev
110-
? browserRouteModulesPlugin_v2(ctx, /\?browser$/, onLoader)
127+
? browserRouteModulesPlugin_v2(ctx, routeModulePaths, onLoader)
111128
: browserRouteModulesPlugin(ctx, /\?browser$/),
129+
mdxPlugin(ctx),
112130
emptyModulesPlugin(ctx, /\.server(\.[jt]sx?)?$/),
113131
NodeModulesPolyfillPlugin(),
114132
externalPlugin(/^node:.*/, { sideEffects: false }),

0 commit comments

Comments
 (0)