Skip to content

Commit 3eab714

Browse files
beyondkmpmmaietta
andauthored
fix: packages in the workspace not being under node_modules (electron-userland#8576)
fix develar/app-builder#141 reproduced error info ``` ● yarn several workspaces /tmp/et-db411cd21f3bbd882f3a5a30c58db6ff/t-kIKFAh/test-project-2/packages/foo/package.json must be under /tmp/et-db411cd21f3bbd882f3a5a30c58db6ff/t-kIKFAh/test-project-2/packages/test-app/ 30 | const index = file.indexOf(NODE_MODULES_PATTERN) 31 | if (index < 0) { > 32 | throw new Error(`${file} must be under ${srcWithEndSlash}`) | ^ 33 | } else { 34 | return file.substring(index + 1 /* leading slash */) 35 | } at getRelativePath (../packages/app-builder-lib/src/util/filter.ts:32:13) at AsarPackager.unpackPattern (../packages/app-builder-lib/src/util/filter.ts:57:20) at AsarPackager.createPackageFromFiles (../packages/app-builder-lib/src/asar/asarUtil.ts:129:82) at AsarPackager.pack (../packages/app-builder-lib/src/asar/asarUtil.ts:49:41) at ../packages/app-builder-lib/src/platformPackager.ts:439:11 at async Promise.all (index 0) at AsyncTaskManager.awaitTasks (../packages/builder-util/src/asyncTaskManager.ts:65:25) at LinuxPackager.doPack (../packages/app-builder-lib/src/platformPackager.ts:293:5) at LinuxPackager.pack (../packages/app-builder-lib/src/platformPackager.ts:138:5) at Packager.doBuild (../packages/app-builder-lib/src/packager.ts:459:9) at executeFinally (../packages/builder-util/src/promise.ts:12:14) at Packager.build (../packages/app-builder-lib/src/packager.ts:393:31) at packAndCheck (src/helpers/packTester.ts:188:41) at src/helpers/packTester.ts:132:36 at executeFinally (../packages/builder-util/src/promise.ts:12:14) ``` Currently, the returned node_modules paths are no longer symlinks, but resolved paths. For example, packages in pnpm workspace/yarn workspace are not under node_modules. All previous getRealSource/getRelativePath methods were based on node_modules in the path, which was relatively tricky. https://github.com/electron-userland/electron-builder/blob/a25d04d5a8e58b447f0462673a4362414da9ed27/packages/app-builder-lib/src/util/appFileCopier.ts#L191-L203 https://github.com/electron-userland/electron-builder/blob/a25d04d5a8e58b447f0462673a4362414da9ed27/packages/app-builder-lib/src/util/filter.ts#L28-L36 Solution: Directly include relativeNodeModulesPath in the file stats. This is simple and easy to understand. --------- Co-authored-by: Mike Maietta <[email protected]>
1 parent dfa35c3 commit 3eab714

File tree

10 files changed

+183
-52
lines changed

10 files changed

+183
-52
lines changed

Diff for: .changeset/nasty-mangos-yawn.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"app-builder-lib": patch
3+
"builder-util": patch
4+
---
5+
6+
fix: packages in the workspace not being under node_modules

Diff for: packages/app-builder-lib/src/util/AppFileWalker.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Filter, FileConsumer } from "builder-util"
1+
import { Filter, FileConsumer, FilterStats } from "builder-util"
22
import { readlink, stat, Stats } from "fs-extra"
33
import { FileMatcher } from "../fileMatcher"
44
import { Packager } from "../packager"
@@ -41,7 +41,7 @@ export abstract class FileCopyHelper {
4141
return targetFileStat
4242
})
4343
} else {
44-
const s = fileStat as any
44+
const s: FilterStats = fileStat
4545
s.relativeLink = link
4646
s.linkRelativeToFile = path.relative(parent, resolvedLinkTarget)
4747
}

Diff for: packages/app-builder-lib/src/util/NodeModuleCopyHelper.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import BluebirdPromise from "bluebird-lst"
2-
import { CONCURRENCY } from "builder-util"
2+
import { CONCURRENCY, FilterStats } from "builder-util"
33
import { lstat, readdir, lstatSync } from "fs-extra"
44
import * as path from "path"
55
import { excludedNames, FileMatcher } from "../fileMatcher"
@@ -112,7 +112,8 @@ export class NodeModuleCopyHelper extends FileCopyHelper {
112112
}
113113
}
114114

115-
return lstat(filePath).then(stat => {
115+
return lstat(filePath).then((stat: FilterStats) => {
116+
stat.relativeNodeModulesPath = path.join("node_modules", moduleName, path.relative(depPath, filePath))
116117
if (filter != null && !filter(filePath, stat)) {
117118
return null
118119
}

Diff for: packages/app-builder-lib/src/util/appFileCopier.ts

+4-22
Original file line numberDiff line numberDiff line change
@@ -188,42 +188,24 @@ export async function computeNodeModuleFileSets(platformPackager: PlatformPackag
188188
const result = new Array<ResolvedFileSet>()
189189
let index = 0
190190
const NODE_MODULES = "node_modules"
191-
const getRealSource = (name: string, source: string) => {
192-
let parentDir = path.dirname(source)
193191

194-
const scopeDepth = name.split("/").length
195-
// get the parent dir of the package, input: /root/path/node_modules/@electron/remote, output: /root/path/node_modules
196-
for (let i = 0; i < scopeDepth - 1; i++) {
197-
parentDir = path.dirname(parentDir)
198-
}
199-
200-
// for the local node modules which is not in node modules
201-
if (!parentDir.endsWith(path.sep + NODE_MODULES)) {
202-
return parentDir
203-
}
204-
205-
// use main matcher patterns,return parent dir of the node_modules, so user can exclude some files !node_modules/xxxx
206-
return path.dirname(parentDir)
207-
}
208-
209-
const collectNodeModules = async (dep: NodeModuleInfo, realSource: string, destination: string) => {
192+
const collectNodeModules = async (dep: NodeModuleInfo, destination: string) => {
210193
const source = dep.dir
211-
const matcher = new FileMatcher(realSource, destination, mainMatcher.macroExpander, mainMatcher.patterns)
194+
const matcher = new FileMatcher(source, destination, mainMatcher.macroExpander, mainMatcher.patterns)
212195
const copier = new NodeModuleCopyHelper(matcher, platformPackager.info)
213196
const files = await copier.collectNodeModules(dep, nodeModuleExcludedExts)
214197
result[index++] = validateFileSet({ src: source, destination, files, metadata: copier.metadata })
215198

216199
if (dep.conflictDependency) {
217200
for (const c of dep.conflictDependency) {
218-
await collectNodeModules(c, realSource, path.join(destination, NODE_MODULES, c.name))
201+
await collectNodeModules(c, path.join(destination, NODE_MODULES, c.name))
219202
}
220203
}
221204
}
222205

223206
for (const dep of deps) {
224207
const destination = path.join(mainMatcher.to, NODE_MODULES, dep.name)
225-
const realSource = getRealSource(dep.name, dep.dir)
226-
await collectNodeModules(dep, realSource, destination)
208+
await collectNodeModules(dep, destination)
227209
}
228210

229211
return result

Diff for: packages/app-builder-lib/src/util/filter.ts

+5-16
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
import { Filter } from "builder-util"
2-
import { Stats } from "fs-extra"
1+
import { Filter, FilterStats } from "builder-util"
32
import { Minimatch } from "minimatch"
43
import * as path from "path"
5-
import { NODE_MODULES_PATTERN } from "../fileTransformer"
64

75
/** @internal */
86
export function hasMagic(pattern: Minimatch) {
@@ -25,17 +23,8 @@ function ensureEndSlash(s: string) {
2523
return s.length === 0 || s.endsWith(path.sep) ? s : s + path.sep
2624
}
2725

28-
function getRelativePath(file: string, srcWithEndSlash: string) {
29-
if (!file.startsWith(srcWithEndSlash)) {
30-
const index = file.indexOf(NODE_MODULES_PATTERN)
31-
if (index < 0) {
32-
throw new Error(`${file} must be under ${srcWithEndSlash}`)
33-
} else {
34-
return file.substring(index + 1 /* leading slash */)
35-
}
36-
}
37-
38-
let relative = file.substring(srcWithEndSlash.length)
26+
function getRelativePath(file: string, srcWithEndSlash: string, stat: FilterStats) {
27+
let relative = stat.relativeNodeModulesPath || file.substring(srcWithEndSlash.length)
3928
if (path.sep === "\\") {
4029
if (relative.startsWith("\\")) {
4130
// windows problem: double backslash, the above substring call removes root path with a single slash, so here can me some leftovers
@@ -54,7 +43,7 @@ export function createFilter(src: string, patterns: Array<Minimatch>, excludePat
5443
return true
5544
}
5645

57-
let relative = getRelativePath(file, srcWithEndSlash)
46+
let relative = getRelativePath(file, srcWithEndSlash, stat)
5847

5948
// filter the root node_modules, but not a subnode_modules (like /appDir/others/foo/node_modules/blah)
6049
if (relative === "node_modules") {
@@ -69,7 +58,7 @@ export function createFilter(src: string, patterns: Array<Minimatch>, excludePat
6958
}
7059

7160
// https://github.com/joshwnj/minimatch-all/blob/master/index.js
72-
function minimatchAll(path: string, patterns: Array<Minimatch>, stat: Stats): boolean {
61+
function minimatchAll(path: string, patterns: Array<Minimatch>, stat: FilterStats): boolean {
7362
let match = false
7463
for (const pattern of patterns) {
7564
// If we've got a match, only re-test for exclusions.

Diff for: packages/builder-util/src/fs.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,15 @@ export class CopyFileTransformer {
1919
}
2020

2121
export type FileTransformer = (file: string) => Promise<null | string | Buffer | CopyFileTransformer> | null | string | Buffer | CopyFileTransformer
22-
export type Filter = (file: string, stat: Stats) => boolean
22+
export interface FilterStats extends Stats {
23+
// relative path of the dependency(node_modules + moduleName + file)
24+
// Mainly used for filter, such as files filtering and asarUnpack filtering
25+
relativeNodeModulesPath?: string
26+
// deal with asar unpack sysmlink
27+
relativeLink?: string
28+
linkRelativeToFile?: string
29+
}
30+
export type Filter = (file: string, stat: FilterStats) => boolean
2331

2432
export function unlinkIfExists(file: string) {
2533
return unlink(file).catch(() => {

Diff for: test/fixtures/test-app-yarn-several-workspace/packages/foo/package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"main": "index.js",
55
"license": "MIT",
66
"dependencies": {
7-
"ms": "2.0.0",
8-
"electron-log": "2.2.8"
7+
"ms": "2.0.0"
98
}
109
}

Diff for: test/fixtures/test-app-yarn-several-workspace/packages/test-app/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
},
2121
"dependencies": {
2222
"ms": "2.0.0",
23-
"electron-log": "2.2.9"
23+
"electron-log": "2.2.9",
24+
"foo": "*"
2425
}
2526
}

Diff for: test/snapshots/HoistedNodeModuleTest.js.snap

+135-6
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,11 @@ exports[`yarn several workspaces 2`] = `
8383
Object {
8484
"files": Object {
8585
"index.html": Object {
86-
"offset": "19060",
86+
"offset": "19187",
8787
"size": 841,
8888
},
8989
"index.js": Object {
90-
"offset": "19901",
90+
"offset": "20028",
9191
"size": 2501,
9292
},
9393
"node_modules": Object {
@@ -160,27 +160,156 @@ Object {
160160
},
161161
},
162162
},
163+
"foo": Object {
164+
"files": Object {
165+
"package.json": Object {
166+
"offset": "14750",
167+
"size": 127,
168+
},
169+
},
170+
},
163171
"ms": Object {
164172
"files": Object {
165173
"index.js": Object {
174+
"offset": "14877",
175+
"size": 2764,
176+
},
177+
"license.md": Object {
178+
"offset": "17641",
179+
"size": 1077,
180+
},
181+
"package.json": Object {
182+
"offset": "18718",
183+
"size": 469,
184+
},
185+
},
186+
},
187+
},
188+
},
189+
"package.json": Object {
190+
"offset": "22529",
191+
"size": 326,
192+
},
193+
},
194+
}
195+
`;
196+
197+
exports[`yarn several workspaces and asarUnpack 1`] = `
198+
Object {
199+
"linux": Array [],
200+
}
201+
`;
202+
203+
exports[`yarn several workspaces and asarUnpack 2`] = `
204+
Object {
205+
"files": Object {
206+
"index.html": Object {
207+
"offset": "14877",
208+
"size": 841,
209+
},
210+
"index.js": Object {
211+
"offset": "15718",
212+
"size": 2501,
213+
},
214+
"node_modules": Object {
215+
"files": Object {
216+
"electron-log": Object {
217+
"files": Object {
218+
"LICENSE": Object {
219+
"offset": "0",
220+
"size": 1082,
221+
},
222+
"index.js": Object {
223+
"offset": "1082",
224+
"size": 140,
225+
},
226+
"lib": Object {
227+
"files": Object {
228+
"format.js": Object {
229+
"offset": "1222",
230+
"size": 1021,
231+
},
232+
"log.js": Object {
233+
"offset": "2243",
234+
"size": 877,
235+
},
236+
"transports": Object {
237+
"files": Object {
238+
"console.js": Object {
239+
"offset": "3120",
240+
"size": 343,
241+
},
242+
"file": Object {
243+
"files": Object {
244+
"find-log-path.js": Object {
245+
"offset": "3463",
246+
"size": 2078,
247+
},
248+
"get-app-name.js": Object {
249+
"offset": "5541",
250+
"size": 1780,
251+
},
252+
"index.js": Object {
253+
"offset": "7321",
254+
"size": 2068,
255+
},
256+
},
257+
},
258+
"log-s.js": Object {
259+
"offset": "9389",
260+
"size": 1751,
261+
},
262+
"renderer-console.js": Object {
263+
"offset": "11140",
264+
"size": 544,
265+
},
266+
},
267+
},
268+
},
269+
},
270+
"main.js": Object {
271+
"offset": "11684",
272+
"size": 1343,
273+
},
274+
"package.json": Object {
275+
"offset": "13027",
276+
"size": 745,
277+
},
278+
"renderer.js": Object {
279+
"offset": "13772",
280+
"size": 978,
281+
},
282+
},
283+
},
284+
"foo": Object {
285+
"files": Object {
286+
"package.json": Object {
166287
"offset": "14750",
288+
"size": 127,
289+
},
290+
},
291+
},
292+
"ms": Object {
293+
"files": Object {
294+
"index.js": Object {
167295
"size": 2764,
296+
"unpacked": true,
168297
},
169298
"license.md": Object {
170-
"offset": "17514",
171299
"size": 1077,
300+
"unpacked": true,
172301
},
173302
"package.json": Object {
174-
"offset": "18591",
175303
"size": 469,
304+
"unpacked": true,
176305
},
177306
},
178307
},
179308
},
180309
},
181310
"package.json": Object {
182-
"offset": "22402",
183-
"size": 310,
311+
"offset": "18219",
312+
"size": 326,
184313
},
185314
},
186315
}

Diff for: test/src/HoistedNodeModuleTest.ts

+16
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,22 @@ test.ifAll("yarn several workspaces", () =>
4040
)
4141
)
4242

43+
test.ifAll("yarn several workspaces and asarUnpack", () =>
44+
assertPack(
45+
"test-app-yarn-several-workspace",
46+
{
47+
targets: linuxDirTarget,
48+
projectDir: "packages/test-app",
49+
config: {
50+
asarUnpack: ["**/node_modules/ms/**/*"],
51+
},
52+
},
53+
{
54+
packed: context => verifyAsarFileTree(context.getResources(Platform.LINUX)),
55+
}
56+
)
57+
)
58+
4359
test.ifAll("yarn two package.json w/ native module", () =>
4460
assertPack(
4561
"test-app-two-native-modules",

0 commit comments

Comments
 (0)