forked from denoland/deno
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rollup.config.js
334 lines (298 loc) · 10.6 KB
/
rollup.config.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
// @ts-check
import * as fs from "fs";
import path from "path";
import alias from "rollup-plugin-alias";
import { plugin as analyze } from "rollup-plugin-analyzer";
import commonjs from "rollup-plugin-commonjs";
import globals from "rollup-plugin-node-globals";
import nodeResolve from "rollup-plugin-node-resolve";
import typescriptPlugin from "rollup-plugin-typescript2";
import { createFilter } from "rollup-pluginutils";
import typescript from "typescript";
import MagicString from "magic-string";
const mockPath = path.resolve(__dirname, "js/mock_builtin.js");
const platformPath = path.resolve(__dirname, "js/platform.ts");
const tsconfig = path.resolve(__dirname, "tsconfig.json");
const typescriptPath = path.resolve(
__dirname,
"third_party/node_modules/typescript/lib/typescript.js"
);
// We will allow generated modules to be resolvable by TypeScript based on
// the current build path
const tsconfigOverride = {
compilerOptions: {
paths: {
"*": ["*", path.resolve("*")]
}
}
};
/** this is a rollup plugin which will look for imports ending with `!string` and resolve
* them with a module that will inline the contents of the file as a string. Needed to
* support `js/assets.ts`.
* @param {any} param0
*/
function strings(
{ include, exclude } = { include: undefined, exclude: undefined }
) {
if (!include) {
throw new Error("include option must be passed");
}
const filter = createFilter(include, exclude);
return {
name: "strings",
/**
* @param {string} importee
*/
resolveId(importee) {
if (importee.endsWith("!string")) {
// strip the `!string` from `importee`
importee = importee.slice(0, importee.lastIndexOf("!string"));
if (!importee.startsWith("gen/")) {
// this is a static asset which is located relative to the root of
// the source project
return path.resolve(path.join(__dirname, importee));
}
// this is an asset which has been generated, therefore it will be
// located within the build path
return path.resolve(path.join(process.cwd(), importee));
}
},
/**
* @param {any} code
* @param {string} id
*/
transform(code, id) {
if (filter(id)) {
return {
code: `export default ${JSON.stringify(code)};`,
map: { mappings: "" }
};
}
}
};
}
const archNodeToDeno = {
x64: "x64"
};
const osNodeToDeno = {
win32: "win",
darwin: "mac",
linux: "linux"
};
/** Inject deno.platform.arch and deno.platform.os
* @param {any} param0
*/
function platform({ include, exclude } = {}) {
if (!include) {
throw new Error("include option must be passed");
}
const filter = createFilter(include, exclude);
return {
name: "platform",
/**
* @param {any} _code
* @param {string} id
*/
transform(_code, id) {
if (filter(id)) {
// Adapted from https://github.com/rollup/rollup-plugin-inject/blob/master/src/index.js
const arch = archNodeToDeno[process.arch];
const os = osNodeToDeno[process.platform];
// We do not have to worry about the interface here, because this is just to generate
// the actual runtime code, not any type information integrated into Deno
const magicString = new MagicString(`
export const platform = { arch: "${arch}", os:"${os}" };`);
return {
code: magicString.toString(),
map: magicString.generateMap()
};
}
}
};
}
// This plugin resolves at bundle time any generated resources that are
// in the build path under `gen` and specified with a MID starting with `gen/`.
// The plugin assumes that the MID needs to have the `.ts` extension appended.
function resolveGenerated() {
return {
name: "resolve-msg-generated",
resolveId(importee) {
if (importee.startsWith("gen/msg_generated")) {
return path.resolve(`${importee}.ts`);
}
}
};
}
function generateDepFile({ outputFile, sourceFiles = [], configFiles = [] }) {
let timestamp = new Date();
// Save the depfile just before the node process exits.
process.once("beforeExit", () =>
writeDepFile({ outputFile, sourceFiles, configFiles, timestamp })
);
return {
name: "depfile",
load(sourceFile) {
// The 'globals' plugin adds generated files that don't exist on disk.
// Don't add them to the depfile.
if (/^[0-9a-f]{30}$/.test(sourceFile)) {
return;
}
sourceFiles.push(sourceFile);
// Remember the time stamp that we last resolved a dependency.
// We'll set the last modified time of the depfile to that.
timestamp = new Date();
}
};
}
function writeDepFile({ outputFile, sourceFiles, configFiles, timestamp }) {
const buildDir = process.cwd();
const outputDir = path.dirname(outputFile);
// Assert that the discovered bundle inputs are files that exist on disk.
sourceFiles.forEach(f => fs.accessSync(f));
// Since we also want to rebuild the bundle if rollup configuration or the the
// tooling changes (e.g. when typescript is updated), add the currently loaded
// node.js modules to the list of dependencies.
let inputs = [...sourceFiles, ...configFiles, ...Object.keys(require.cache)];
// Deduplicate the list of inputs.
inputs = Array.from(new Set(inputs.map(f => path.resolve(f))));
// Turn filenames into relative paths and format/escape them for a Makefile.
inputs = inputs.map(formatPath);
// Build a list of output filenames and normalize those too.
const depFile = path.join(
outputDir,
path.basename(outputFile, path.extname(outputFile)) + ".d"
);
const outputs = [outputFile, depFile].map(formatPath);
// Generate depfile contents.
const depFileContent = [
...outputs.map(filename => `${filename}: ` + inputs.join(" ") + "\n\n"),
...inputs.map(filename => `${filename}:\n`)
].join("");
// Since we're writing the depfile when node's "beforeExit" hook triggers,
// it's getting written _after_ the regular outputs are saved to disk.
// Therefore, after writing the depfile, reset its timestamps to when we last
// discovered a dependency, which was certainly before the bundle was built.
fs.writeFileSync(depFile, depFileContent);
fs.utimesSync(depFile, timestamp, timestamp);
// Renders path to make it suitable for a depfile.
function formatPath(filename) {
// Make the path relative to the root build directory.
filename = path.relative(buildDir, filename);
// Use forward slashes on Windows.
if (process.platform === "win32") {
filename = filename.replace(/\\/g, "/");
}
// Escape spaces with a backslash. This is what rust and clang do too.
filename = filename.replace(/ /g, "\\ ");
return filename;
}
}
export default function makeConfig(commandOptions) {
return {
output: {
format: "iife",
name: "denoMain",
sourcemap: true,
sourcemapExcludeSources: true
},
plugins: [
// inject platform and arch from Node
platform({
include: [platformPath]
}),
// would prefer to use `rollup-plugin-virtual` to inject the empty module, but there
// is an issue with `rollup-plugin-commonjs` which causes errors when using the
// virtual plugin (see: rollup/rollup-plugin-commonjs#315), this means we have to use
// a physical module to substitute
alias({
fs: mockPath,
path: mockPath,
os: mockPath,
crypto: mockPath,
buffer: mockPath,
module: mockPath
}),
// Provides inlining of file contents for `js/assets.ts`
strings({
include: [
"*.d.ts",
`${__dirname}/**/*.d.ts`,
`${process.cwd()}/**/*.d.ts`
]
}),
// Resolves any resources that have been generated at build time
resolveGenerated(),
// Allows rollup to resolve modules based on Node.js resolution
nodeResolve({
jsnext: true,
main: true
}),
// Allows rollup to import CommonJS modules
commonjs({
namedExports: {
// Static analysis of `typescript.js` does detect the exports properly, therefore
// rollup requires them to be explicitly defined to make them available in the
// bundle
[typescriptPath]: [
"createLanguageService",
"formatDiagnosticsWithColorAndContext",
"ModuleKind",
"ScriptKind",
"ScriptSnapshot",
"ScriptTarget",
"version"
]
}
}),
typescriptPlugin({
// The build script is invoked from `out/:target` so passing an absolute file path is needed
tsconfig,
// This provides any overrides to the `tsconfig.json` that are needed to bundle
tsconfigOverride,
// This provides the locally configured version of TypeScript instead of the plugins
// default version
typescript,
// By default, the include path only includes the cwd and below, need to include the root of the project
// and build path to be passed to this plugin. This is different front tsconfig.json include
include: ["*.ts", `${__dirname}/**/*.ts`, `${process.cwd()}/**/*.ts`],
// d.ts files are not bundled and by default like include, it only includes the cwd and below
exclude: [
"*.d.ts",
`${__dirname}/**/*.d.ts`,
`${process.cwd()}/**/*.d.ts`
]
}),
// Provide some concise information about the bundle
analyze({
skipFormatted: true,
onAnalysis({
bundleSize,
bundleOrigSize,
bundleReduction,
moduleCount
}) {
if (!commandOptions.silent) {
console.log(
`Bundle size: ${Math.round((bundleSize / 1000000) * 100) / 100}Mb`
);
console.log(
`Original size: ${Math.round((bundleOrigSize / 1000000) * 100) /
100}Mb`
);
console.log(`Reduction: ${bundleReduction}%`);
console.log(`Module count: ${moduleCount}`);
}
}
}),
// source-map-support, which is required by TypeScript to support source maps, requires Node.js Buffer
// implementation. This needs to come at the end of the plugins because of the impact it has on
// the existing runtime environment, which breaks other plugins and features of the bundler.
globals(),
generateDepFile({
outputFile: commandOptions.o,
configFiles: [commandOptions.c, tsconfig]
})
]
};
}