Skip to content

Commit 5b26311

Browse files
authored
fix: don't use windows path separators for path templating in monorepo (#293)
* fix: always use posix paths in JS imports * chore: teach windows paths to test * chore: reenable some fixed tests * chore: add comment about path conversion * revert changes to integration tests
1 parent 077cc18 commit 5b26311

File tree

3 files changed

+38
-30
lines changed

3 files changed

+38
-30
lines changed

src/build/content/static.test.ts

+18-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Buffer } from 'node:buffer'
22
import { join } from 'node:path'
3-
import { platform } from 'node:process'
43

54
import type { NetlifyPluginOptions } from '@netlify/build'
65
import glob from 'fast-glob'
@@ -30,7 +29,15 @@ const createFsFixtureWithBasePath = (
3029
)
3130
}
3231

33-
describe.skipIf(platform === 'win32')('Regular Repository layout', () => {
32+
async function readDirRecursive(dir: string) {
33+
const posixPaths = await glob('**/*', { cwd: dir, dot: true, absolute: true })
34+
// glob always returns unix-style paths, even on Windows!
35+
// To compare them more easily in our tests running on Windows, we convert them to the platform-specific paths.
36+
const paths = posixPaths.map((posixPath) => join(posixPath))
37+
return paths
38+
}
39+
40+
describe('Regular Repository layout', () => {
3441
beforeEach<Context>((ctx) => {
3542
ctx.publishDir = '.next'
3643
ctx.pluginContext = new PluginContext({
@@ -64,7 +71,7 @@ describe.skipIf(platform === 'win32')('Regular Repository layout', () => {
6471
)
6572

6673
await copyStaticAssets(pluginContext)
67-
expect(await glob('**/*', { cwd, dot: true, absolute: true })).toEqual(
74+
expect(await readDirRecursive(cwd)).toEqual(
6875
expect.arrayContaining([
6976
join(cwd, '.next/static/test.js'),
7077
join(cwd, '.next/static/sub-dir/test2.js'),
@@ -88,7 +95,7 @@ describe.skipIf(platform === 'win32')('Regular Repository layout', () => {
8895
)
8996

9097
await copyStaticAssets(pluginContext)
91-
expect(await glob('**/*', { cwd, dot: true, absolute: true })).toEqual(
98+
expect(await readDirRecursive(cwd)).toEqual(
9299
expect.arrayContaining([
93100
join(cwd, '.next/static/test.js'),
94101
join(cwd, '.next/static/sub-dir/test2.js'),
@@ -111,7 +118,7 @@ describe.skipIf(platform === 'win32')('Regular Repository layout', () => {
111118
)
112119

113120
await copyStaticAssets(pluginContext)
114-
expect(await glob('**/*', { cwd, dot: true, absolute: true })).toEqual(
121+
expect(await readDirRecursive(cwd)).toEqual(
115122
expect.arrayContaining([
116123
join(cwd, 'public/another-asset.json'),
117124
join(cwd, 'public/fake-image.svg'),
@@ -135,7 +142,7 @@ describe.skipIf(platform === 'win32')('Regular Repository layout', () => {
135142
)
136143

137144
await copyStaticAssets(pluginContext)
138-
expect(await glob('**/*', { cwd, dot: true, absolute: true })).toEqual(
145+
expect(await readDirRecursive(cwd)).toEqual(
139146
expect.arrayContaining([
140147
join(cwd, 'public/another-asset.json'),
141148
join(cwd, 'public/fake-image.svg'),
@@ -186,7 +193,7 @@ describe.skipIf(platform === 'win32')('Regular Repository layout', () => {
186193
})
187194
})
188195

189-
describe.skipIf(platform === 'win32')('Mono Repository', () => {
196+
describe('Mono Repository', () => {
190197
beforeEach<Context>((ctx) => {
191198
ctx.publishDir = 'apps/app-1/.next'
192199
ctx.pluginContext = new PluginContext({
@@ -211,7 +218,7 @@ describe.skipIf(platform === 'win32')('Mono Repository', () => {
211218
)
212219

213220
await copyStaticAssets(pluginContext)
214-
expect(await glob('**/*', { cwd, dot: true, absolute: true })).toEqual(
221+
expect(await readDirRecursive(cwd)).toEqual(
215222
expect.arrayContaining([
216223
join(cwd, 'apps/app-1/.next/static/test.js'),
217224
join(cwd, 'apps/app-1/.next/static/sub-dir/test2.js'),
@@ -235,7 +242,7 @@ describe.skipIf(platform === 'win32')('Mono Repository', () => {
235242
)
236243

237244
await copyStaticAssets(pluginContext)
238-
expect(await glob('**/*', { cwd, dot: true, absolute: true })).toEqual(
245+
expect(await readDirRecursive(cwd)).toEqual(
239246
expect.arrayContaining([
240247
join(cwd, 'apps/app-1/.next/static/test.js'),
241248
join(cwd, 'apps/app-1/.next/static/sub-dir/test2.js'),
@@ -258,7 +265,7 @@ describe.skipIf(platform === 'win32')('Mono Repository', () => {
258265
)
259266

260267
await copyStaticAssets(pluginContext)
261-
expect(await glob('**/*', { cwd, dot: true, absolute: true })).toEqual(
268+
expect(await readDirRecursive(cwd)).toEqual(
262269
expect.arrayContaining([
263270
join(cwd, 'apps/app-1/public/another-asset.json'),
264271
join(cwd, 'apps/app-1/public/fake-image.svg'),
@@ -282,7 +289,7 @@ describe.skipIf(platform === 'win32')('Mono Repository', () => {
282289
)
283290

284291
await copyStaticAssets(pluginContext)
285-
expect(await glob('**/*', { cwd, dot: true, absolute: true })).toEqual(
292+
expect(await readDirRecursive(cwd)).toEqual(
286293
expect.arrayContaining([
287294
join(cwd, 'apps/app-1/public/another-asset.json'),
288295
join(cwd, 'apps/app-1/public/fake-image.svg'),

src/build/functions/server.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { cp, mkdir, readFile, rm, writeFile } from 'fs/promises'
2-
import { join } from 'node:path'
3-
import { relative } from 'path'
2+
import { join, relative } from 'node:path'
3+
import { join as posixJoin } from 'node:path/posix'
44

55
import { glob } from 'fast-glob'
66

@@ -83,8 +83,8 @@ const getHandlerFile = async (ctx: PluginContext): Promise<string> => {
8383
const template = await readFile(join(templatesDir, 'handler-monorepo.tmpl.js'), 'utf-8')
8484

8585
return template
86-
.replaceAll('{{cwd}}', ctx.lambdaWorkingDirectory)
87-
.replace('{{nextServerHandler}}', ctx.nextServerHandler)
86+
.replaceAll('{{cwd}}', posixJoin(ctx.lambdaWorkingDirectory))
87+
.replace('{{nextServerHandler}}', posixJoin(ctx.nextServerHandler))
8888
}
8989

9090
return await readFile(join(templatesDir, 'handler.tmpl.js'), 'utf-8')

src/build/plugin-context.test.ts

+16-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { join } from 'node:path'
2-
import { platform } from 'node:process'
32

43
import { NetlifyPluginOptions } from '@netlify/build'
54
import { expect, test, vi } from 'vitest'
@@ -59,14 +58,14 @@ test('next app with custom distDir', () => {
5958
expect(ctx.publishDir).toBe(join(cwd, 'out'))
6059
})
6160

62-
test.skipIf(platform === 'win32')('next app with deep custom distDir', () => {
61+
test('next app with deep custom distDir', () => {
6362
const { cwd } = mockFileSystem({
6463
'out/dir/required-server-files.json': JSON.stringify({ config: { distDir: 'out/dir' } }),
6564
})
6665
const ctx = new PluginContext({ constants: { PUBLISH_DIR: 'out/dir' } } as NetlifyPluginOptions)
6766
expect(ctx.standaloneDir).toBe(join(cwd, 'out/dir/standalone/out'))
6867
expect(ctx.standaloneRootDir).toBe(join(cwd, 'out/dir/standalone'))
69-
expect(ctx.distDir).toBe('out/dir')
68+
expect(ctx.distDir).toBe(join('out', 'dir'))
7069
expect(ctx.distDirParent).toBe('out')
7170
expect(ctx.nextDistDir).toBe('dir')
7271
expect(ctx.relPublishDir).toBe('out/dir')
@@ -76,7 +75,7 @@ test.skipIf(platform === 'win32')('next app with deep custom distDir', () => {
7675
)
7776
})
7877

79-
test.skipIf(platform === 'win32')('monorepo with package path', () => {
78+
test('monorepo with package path', () => {
8079
const { cwd } = mockFileSystem({
8180
'apps/my-app/.next/required-server-files.json': JSON.stringify({
8281
config: { distDir: '.next' },
@@ -91,8 +90,10 @@ test.skipIf(platform === 'win32')('monorepo with package path', () => {
9190
expect(ctx.edgeHandlerDir).toBe(
9291
join(cwd, 'apps/my-app/.netlify/edge-functions/___netlify-edge-handler'),
9392
)
94-
expect(ctx.lambdaWorkingDirectory).toBe('/var/task/apps/my-app')
95-
expect(ctx.nextServerHandler).toBe('/var/task/apps/my-app/.netlify/dist/run/handlers/server.js')
93+
expect(ctx.lambdaWorkingDirectory).toBe(join('/var/task/apps/my-app'))
94+
expect(ctx.nextServerHandler).toBe(
95+
join('/var/task/apps/my-app/.netlify/dist/run/handlers/server.js'),
96+
)
9697
expect(ctx.serverFunctionsDir).toBe(join(cwd, 'apps/my-app/.netlify/functions-internal'))
9798
expect(ctx.serverHandlerDir).toBe(
9899
join(cwd, 'apps/my-app/.netlify/functions-internal/___netlify-server-handler/apps/my-app'),
@@ -103,14 +104,14 @@ test.skipIf(platform === 'win32')('monorepo with package path', () => {
103104
expect(ctx.standaloneDir).toBe(join(cwd, 'apps/my-app/.next/standalone/apps/my-app'))
104105
expect(ctx.standaloneRootDir).toBe(join(cwd, 'apps/my-app/.next/standalone'))
105106
expect(ctx.staticDir).toBe(join(cwd, 'apps/my-app/.netlify/static'))
106-
expect(ctx.distDir).toBe('apps/my-app/.next')
107-
expect(ctx.distDirParent).toBe('apps/my-app')
107+
expect(ctx.distDir).toBe(join('apps/my-app/.next'))
108+
expect(ctx.distDirParent).toBe(join('apps/my-app'))
108109
expect(ctx.nextDistDir).toBe('.next')
109-
expect(ctx.relPublishDir).toBe('apps/my-app/.next')
110+
expect(ctx.relPublishDir).toBe(join('apps/my-app/.next'))
110111
expect(ctx.publishDir).toBe(join(cwd, 'apps/my-app/.next'))
111112
})
112113

113-
test.skipIf(platform === 'win32')('nx monorepo with package path and different distDir', () => {
114+
test('nx monorepo with package path and different distDir', () => {
114115
const { cwd } = mockFileSystem({
115116
'dist/apps/my-app/.next/required-server-files.json': JSON.stringify({
116117
config: { distDir: '../../dist/apps/my-app/.next' },
@@ -128,9 +129,9 @@ test.skipIf(platform === 'win32')('nx monorepo with package path and different d
128129
expect(ctx.edgeHandlerDir).toBe(
129130
join(cwd, 'apps/my-app/.netlify/edge-functions/___netlify-edge-handler'),
130131
)
131-
expect(ctx.lambdaWorkingDirectory).toBe('/var/task/dist/apps/my-app')
132+
expect(ctx.lambdaWorkingDirectory).toBe(join('/var/task/dist/apps/my-app'))
132133
expect(ctx.nextServerHandler).toBe(
133-
'/var/task/dist/apps/my-app/.netlify/dist/run/handlers/server.js',
134+
join('/var/task/dist/apps/my-app/.netlify/dist/run/handlers/server.js'),
134135
)
135136
expect(ctx.serverFunctionsDir).toBe(join(cwd, 'apps/my-app/.netlify/functions-internal'))
136137
expect(ctx.serverHandlerDir).toBe(
@@ -142,9 +143,9 @@ test.skipIf(platform === 'win32')('nx monorepo with package path and different d
142143
expect(ctx.standaloneDir).toBe(join(cwd, 'dist/apps/my-app/.next/standalone/dist/apps/my-app'))
143144
expect(ctx.standaloneRootDir).toBe(join(cwd, 'dist/apps/my-app/.next/standalone'))
144145
expect(ctx.staticDir).toBe(join(cwd, 'apps/my-app/.netlify/static'))
145-
expect(ctx.distDir).toBe('dist/apps/my-app/.next')
146-
expect(ctx.distDirParent).toBe('dist/apps/my-app')
147-
expect(ctx.nextDistDir).toBe('.next')
146+
expect(ctx.distDir).toBe(join('dist/apps/my-app/.next'))
147+
expect(ctx.distDirParent).toBe(join('dist/apps/my-app'))
148+
expect(ctx.nextDistDir).toBe(join('.next'))
148149
expect(ctx.relPublishDir).toBe('dist/apps/my-app/.next')
149150
expect(ctx.publishDir).toBe(join(cwd, 'dist/apps/my-app/.next'))
150151
})

0 commit comments

Comments
 (0)