-
Notifications
You must be signed in to change notification settings - Fork 546
/
Copy pathesbuildUtils.js
142 lines (131 loc) · 5.31 KB
/
esbuildUtils.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import fs from "fs-extra"
import path from "node:path"
import { dependencyMap } from "./RollupConfig.js"
import { aliasPath as esbuildPluginAliasPath } from "esbuild-plugin-alias-path"
import { getNativeLibModulePaths } from "./nativeLibraryProvider.js"
/**
* Little plugin that obtains compiled better-sqlite3, copies it to dstPath and sets the path to nativeBindingPath.
* We do not use default file loader from esbuild, it is much simpler and reliable to do it manually, and it doesn't work for dynamic import (like in this case)
* anyway.
* It will also replace `buildOptions.sqliteNativePath` with the nativeBindingPath
*/
export function sqliteNativePlugin({ environment, dstPath, nativeBindingPath, platform, architecture }) {
return {
name: "sqlite-native-plugin",
setup(build) {
const options = build.initialOptions
options.define = options.define ?? {}
const nativeLibPath = nativeBindingPath ?? dstPath
// Replace mentions of buildOptions.sqliteNativePath with the actual path
options.define["buildOptions.sqliteNativePath"] = `"${nativeLibPath}"`
build.onStart(async () => {
const modulePaths = await getNativeLibModulePaths({
nodeModule: "better-sqlite3",
environment,
rootDir: process.cwd(),
log: console.log.bind(console),
platform,
architecture,
copyTarget: "better_sqlite3",
})
await fs.promises.mkdir(path.dirname(dstPath), { recursive: true })
await fs.promises.copyFile(modulePaths[process.arch], dstPath)
})
},
}
}
export function mimimiNativePlugin({ dstPath, platform }) {
return {
name: "mimimi-native-plugin",
setup(build) {
const options = build.initialOptions
options.define = options.define ?? {}
build.onStart(async () => {
let nativeBinaryName
switch (platform) {
case "linux":
nativeBinaryName = "node-mimimi.linux-x64-gnu.node"
break
case "win32":
nativeBinaryName = "node-mimimi.win32-x64-msvc.node"
break
case "darwin":
// this is a dev build, so we always take the native arch.
nativeBinaryName = `node-mimimi.darwin-${process.arch}.node`
break
default:
throw Error(`could not find node-mimimi binary: platform ${platform} is unknown`)
}
// Replace mentions of buildOptions.mimimiNativePath with the actual path
options.define["buildOptions.mimimiNativePath"] = `"./${nativeBinaryName}"`
const nativeBinarySourcePath = path.join(process.cwd(), "./packages/node-mimimi/dist", nativeBinaryName)
await fs.mkdir(path.join(process.cwd(), dstPath), { recursive: true })
await fs.promises.copyFile(nativeBinarySourcePath, path.join(process.cwd(), dstPath, nativeBinaryName))
})
},
}
}
/** Little plugin that replaces imports for libs from dependencyMap with their prebuilt versions in libs directory. */
export function libDeps(prefix = ".") {
const absoluteDependencyMap = Object.fromEntries(
Object.entries(dependencyMap).map(([k, v]) => {
return [k, path.resolve(prefix, v)]
}),
)
return esbuildPluginAliasPath({
alias: absoluteDependencyMap,
})
}
/** Little plugin that prepends env */
export function preludeEnvPlugin(env) {
return {
name: "prelude-env",
setup(build) {
const options = build.initialOptions
options.banner = options.banner ?? {}
const bannerStart = options.banner["js"] ? options.banner["js"] + "\n" : ""
options.banner["js"] = bannerStart + `globalThis.env = ${JSON.stringify(env, null, 2)};`
},
}
}
/** Do not embed translations in the source, compile them separately so that ouput is not as huge. */
export function externalTranslationsPlugin() {
const nodePath = path
return {
name: "skip-translations",
setup(build) {
build.onResolve({ filter: /.*\/translations\/.+$/, namespace: "file" }, ({ path }) => {
// We replace all the translation imports.
// We should go from ../../translations/en.js to ./translations/en.mjs
// Out output structure is always flat (except for desktop which is it's own flat structure) so we know that we can find translations in the
// ./translations
// We marked them as external because we don't want esbuild to roll them up, it makes output *huge*
// We add .mjs suffix so that we can import it from Electron without issues (more on that below). This is not necessary for of web but doesn't
// hurt either.
const parsedPath = nodePath.parse(path)
const newPath = `./translations/${parsedPath.name}.mjs`
return {
path: newPath,
external: true,
}
})
build.onEnd(async () => {
// After the main build is done we go and compile all translations. Alternatively we could collect all imports from onResolve().
const translations = await globby("src/mail-app/translations/*.ts")
await build.esbuild.build({
// Always esm, even though desktop is compiled to commonjs because translations do `export default` and esbuild doesn't pick the correct
// interop.
// see https://esbuild.github.io/content-types/#default-interop
format: "esm",
outdir: build.initialOptions.outdir,
entryPoints: translations,
// Rename it to .mjs for reasons mentioned above
outExtension: { [".js"]: ".mjs" },
// So that it outputs build/translations/de.js instead of build/de.js
// (or build/desktop/translations/de.js instead of build/desktop/de.js)
outbase: "src/mail-app",
})
})
},
}
}