-
Notifications
You must be signed in to change notification settings - Fork 405
/
Copy pathrollup.config.js
168 lines (147 loc) · 6.76 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
/*
* Copyright (c) 2024, Salesforce, Inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
/* eslint-env node */
const { readFileSync } = require('node:fs');
const path = require('node:path');
const MagicString = require('magic-string');
const { rollup } = require('rollup');
const replace = require('@rollup/plugin-replace');
const typescript = require('@rollup/plugin-typescript');
const { nodeResolve } = require('@rollup/plugin-node-resolve');
const { BUNDLED_DEPENDENCIES } = require('../shared/bundled-dependencies.js');
// The assumption is that the build script for each sub-package runs in that sub-package's directory
const packageRoot = process.cwd();
const packageJson = JSON.parse(readFileSync(path.resolve(packageRoot, './package.json'), 'utf-8'));
const { name: packageName, version, dependencies, peerDependencies } = packageJson;
// This copyright text should match the text in the header/header eslint rule
let banner = `/**\n * Copyright (c) ${new Date().getFullYear()} Salesforce, Inc.\n */`;
let footer = `/** version: ${version} */`;
const { ROLLUP_WATCH: watchMode } = process.env;
const formats = ['es', 'cjs'];
if (packageName === '@lwc/synthetic-shadow') {
// Here we wrap all of synthetic shadow in a check for lwcRuntimeFlags.ENABLE_FORCE_SHADOW_MIGRATE_MODE and
// lwcRuntimeFlags.DISABLE_SYNTHETIC_SHADOW, so that synthetic shadow is not loaded if either flag is set.
// Note that lwcRuntimeFlags must be referenced as a pure global, or else string replacement in ESBuild
// will not work. But we also have to check to make sure that lwcRuntimeFlags is defined, so this
// `Object.defineProperty` code is copied from @lwc/features itself.
banner += `
if (!globalThis.lwcRuntimeFlags) {
Object.defineProperty(globalThis, 'lwcRuntimeFlags', { value: Object.create(null) });
}
if (!lwcRuntimeFlags.ENABLE_FORCE_SHADOW_MIGRATE_MODE && !lwcRuntimeFlags.DISABLE_SYNTHETIC_SHADOW) {
`
.replaceAll(/\n {4}/g, '\n')
.trimEnd();
footer += '\n}';
}
const onwarn = ({ code, message }) => {
if (!process.env.ROLLUP_WATCH && code !== 'CIRCULAR_DEPENDENCY') {
throw new Error(message);
}
};
// These plugins are used both by the main Rollup build as well as our sub-Rollup build (injectInlineRenderer).
function sharedPlugins() {
const engineBrowserConfig = ['@lwc/engine-server', '@lwc/engine-dom'].includes(packageName) && {
// This is only used inside @lwc/engine-dom and @lwc/engine-server
// Elsewhere, it _not_ be replaced, so that it can be replaced later (e.g. in @lwc/engine-core)
'process.env.IS_BROWSER': packageName === '@lwc/engine-dom' ? 'true' : 'false',
};
return [
typescript({
tsconfig: path.join(packageRoot, 'tsconfig.json'),
exclude: ['**/__tests__/**'],
noEmitOnError: !watchMode, // in watch mode, do not exit with an error if typechecking fails
...(watchMode && {
incremental: true,
outputToFilesystem: true,
}),
declarationDir: 'dist', // must match `output.file` in the overall Rollup config
}),
replace({
values: {
...engineBrowserConfig,
'process.env.LWC_VERSION': JSON.stringify(version),
},
preventAssignment: true,
}),
];
}
// Only used for @lwc/engine-dom
// The renderer in the renderer factory needs to be inlined in the function, with all of its dependencies.
// The reasons for this are due to how Locker does sandboxing.
// So we run Rollup inside of a Rollup plugin to accomplish this. This resolves all dependencies and
// builds them as an IIFE, which can then be injected into the source as process.env.RENDERER.
function injectInlineRenderer() {
const rendererReplacementString = 'process.env.RENDERER';
return {
name: 'inject-inline-renderer',
async transform(source) {
if (source.includes(rendererReplacementString)) {
const bundle = await rollup({
input: path.resolve(
__dirname,
'../../packages/@lwc/engine-dom/src/renderer/index.ts'
),
plugins: [
// In the inline renderer, we only allow certain dependencies. Any others should fail
nodeResolve({
resolveOnly: ['@lwc/shared'],
}),
...sharedPlugins(),
],
onwarn,
});
const { output } = await bundle.generate({
sourcemap: true,
name: 'renderer',
format: 'iife',
esModule: false, // no need for `Object.defineProperty(exports, '__esModule', { value: true })`
});
const { code, modules } = output[0];
// In watch mode, Rollup doesn't know by default that we care about `./renderer/index.ts` or
// its dependencies. If we call `addWatchFile` within the transform hook, Rollup will watch these files.
for (const filename of Object.keys(modules)) {
this.addWatchFile(filename);
}
const magic = new MagicString(source);
// The IIFE will contain the string `var renderer = `, which we don't actually need. We just need the
// part after, which is the actual IIFE (e.g. `(function () { /* code */ })()`)
magic.replace(rendererReplacementString, code.replace('var renderer = ', ''));
return {
code: magic.toString(),
map: magic.generateMap(),
};
}
},
};
}
module.exports = {
input: path.resolve(packageRoot, './src/index.ts'),
output: formats.map((format) => ({
file: `dist/index${format === 'cjs' ? '.cjs' : ''}.js`,
sourcemap: true,
format,
banner,
footer,
exports: 'named',
esModule: true,
})),
plugins: [
nodeResolve({
// These are the dependencies that, when used as devDeps, should be inlined into the dist/ bundles
resolveOnly: [
/^@lwc\//,
// capture the package itself (e.g. `foo`) plus its files (e.g. `foo/bar.js`)
...BUNDLED_DEPENDENCIES.map((dep) => new RegExp(`^${dep}($|/)`)),
],
}),
...sharedPlugins(),
injectInlineRenderer(),
],
onwarn,
external: [...Object.keys(dependencies || {}), ...Object.keys(peerDependencies || {})],
};