UNPKG

9.94 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.load = load;
7exports.preSerialize = preSerialize;
8exports.postDeserialize = postDeserialize;
9
10var _nullthrows = _interopRequireDefault(require("nullthrows"));
11
12var _path = _interopRequireDefault(require("path"));
13
14var bundledBabelCore = _interopRequireWildcard(require("@babel/core"));
15
16var _utils = require("@parcel/utils");
17
18var _env = _interopRequireDefault(require("./env"));
19
20var _jsx = _interopRequireDefault(require("./jsx"));
21
22var _flow = _interopRequireDefault(require("./flow"));
23
24var _typescript = _interopRequireDefault(require("./typescript"));
25
26var _utils2 = require("./utils");
27
28function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
29
30function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
31
32function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
33
34const TYPESCRIPT_EXTNAME_RE = /^\.tsx?/;
35
36const BABEL_TRANSFORMER_DIR = _path.default.dirname(__dirname);
37
38async function load(config, options, logger) {
39 if (config.result != null) {
40 return reload(config, options);
41 } // Don't look for a custom babel config if inside node_modules
42
43
44 if (!config.isSource) {
45 return buildDefaultBabelConfig(config);
46 }
47
48 let babelCore = await loadBabelCore(config, options);
49 let partialConfig = babelCore.loadPartialConfig({
50 filename: config.searchPath,
51 cwd: _path.default.dirname(config.searchPath),
52 root: options.projectRoot
53 }); // loadPartialConfig returns null when the file should explicitly not be run through babel (ignore/exclude)
54
55 if (partialConfig == null) {} else if (partialConfig.hasFilesystemConfig()) {
56 config.setResult({
57 internal: false,
58 config: partialConfig.options,
59 targets: (0, _utils2.enginesToBabelTargets)(config.env)
60 });
61 let {
62 babelrc: babelrcPath,
63 config: configPath
64 } = partialConfig;
65 let {
66 canBeRehydrated,
67 dependsOnRelative,
68 dependsOnLocal
69 } = getStats(partialConfig.options);
70 let configIsJS = typeof babelrcPath === 'string' && _path.default.extname(babelrcPath) === '.js' || typeof configPath === 'string' && _path.default.extname(configPath) === '.js';
71
72 if (configIsJS) {
73 logger.verbose({
74 message: 'WARNING: Using a JavaScript Babel config file means losing out on some caching features of Parcel. Try using a .babelrc file instead.'
75 });
76 config.shouldInvalidateOnStartup(); // babel.config.js files get required by @babel/core so there's no use in setting resolved path for watch mode invalidation
77 } else {
78 config.setResolvedPath(typeof babelrcPath === 'string' ? babelrcPath : configPath);
79 }
80
81 if (babelrcPath && (await isExtended())) {
82 logger.verbose({
83 message: 'WARNING: You are using `extends` in your Babel config, which means you are losing out on some of the caching features of Parcel. Maybe try using a reusable preset instead.'
84 });
85 config.shouldInvalidateOnStartup();
86 }
87
88 if (dependsOnRelative || dependsOnLocal) {
89 logger.verbose({
90 message: 'WARNING: It looks like you are using local Babel plugins or presets. You will need to run with the `--no-cache` option in order to pick up changes to these until their containing package versions are bumped.'
91 });
92 }
93
94 if (canBeRehydrated) {
95 await definePluginDependencies(config);
96 config.setResultHash((0, _utils.md5FromObject)(partialConfig.options));
97 } else {
98 logger.verbose({
99 message: 'WARNING: You are using `require` to configure Babel plugins or presets. This means Babel transformations cannot be cached and will run on each build. Please use strings to configure Babel instead.'
100 });
101 config.setResultHash(JSON.stringify(Date.now()));
102 config.shouldInvalidateOnStartup();
103 }
104 } else {
105 await buildDefaultBabelConfig(config);
106 }
107}
108
109async function buildDefaultBabelConfig(config) {
110 let babelOptions;
111
112 if (_path.default.extname(config.searchPath).match(TYPESCRIPT_EXTNAME_RE)) {
113 babelOptions = (0, _typescript.default)(config);
114 } else {
115 babelOptions = (0, _flow.default)(config);
116 }
117
118 let babelTargets;
119 let envOptions = await (0, _env.default)(config);
120
121 if (envOptions != null) {
122 babelTargets = envOptions.targets;
123 babelOptions = mergeOptions(babelOptions, {
124 presets: envOptions.presets
125 });
126 }
127
128 babelOptions = mergeOptions(babelOptions, (await (0, _jsx.default)(config)));
129
130 if (babelOptions != null) {
131 babelOptions.presets = (babelOptions.presets || []).map(preset => bundledBabelCore.createConfigItem(preset, {
132 type: 'preset',
133 dirname: BABEL_TRANSFORMER_DIR
134 }));
135 babelOptions.plugins = (babelOptions.plugins || []).map(plugin => bundledBabelCore.createConfigItem(plugin, {
136 type: 'plugin',
137 dirname: BABEL_TRANSFORMER_DIR
138 }));
139 }
140
141 config.setResult({
142 internal: true,
143 config: babelOptions,
144 targets: babelTargets
145 });
146 await definePluginDependencies(config);
147}
148
149function mergeOptions(result, config) {
150 if (!config || (!config.presets || config.presets.length === 0) && (!config.plugins || config.plugins.length === 0)) {
151 return result;
152 }
153
154 let merged = result;
155
156 if (merged) {
157 merged.presets = (merged.presets || []).concat(config.presets || []);
158 merged.plugins = (merged.plugins || []).concat(config.plugins || []);
159 } else {
160 result = config;
161 }
162
163 return result;
164}
165
166function getStats(options) {
167 let canBeRehydrated = true;
168 let dependsOnRelative = false;
169 let dependsOnLocal = false;
170 let configItems = [...options.presets, ...options.plugins];
171
172 for (let configItem of configItems) {
173 if (!configItem.file) {
174 canBeRehydrated = false;
175 } else if (configItem.file.request.startsWith('.')) {
176 dependsOnRelative = true;
177 } else if (isLocal()) {
178 dependsOnLocal = true;
179 }
180 }
181
182 return {
183 canBeRehydrated,
184 dependsOnRelative,
185 dependsOnLocal
186 };
187}
188
189function isExtended()
190/* babelrcPath */
191{
192 // TODO: read and parse babelrc and check to see if extends property exists
193 // need access to fs in case of memory filesystem
194 return false;
195}
196
197function isLocal()
198/* configItemPath */
199{
200 // TODO: check if realpath is different, need access to fs in case of memory filesystem
201 return false;
202}
203
204function preSerialize(config) {
205 let babelConfig = config.result.config;
206
207 if (babelConfig == null) {
208 return;
209 } // ConfigItem.value is a function which the v8 serializer chokes on
210 // It is being ommited here and will be rehydrated later using the path provided by ConfigItem.file
211
212
213 babelConfig.presets = (babelConfig.presets || []).map(({
214 options,
215 dirname,
216 name,
217 file
218 }) => ({
219 options,
220 dirname,
221 name,
222 file
223 }));
224 babelConfig.plugins = (babelConfig.plugins || []).map(({
225 options,
226 dirname,
227 name,
228 file
229 }) => ({
230 options,
231 dirname,
232 name,
233 file
234 }));
235}
236
237async function definePluginDependencies(config) {
238 let babelConfig = config.result.config;
239
240 if (babelConfig == null) {
241 return;
242 }
243
244 let configItems = [...babelConfig.presets, ...babelConfig.plugins];
245 await Promise.all(configItems.map(async configItem => {
246 let pkg = (0, _nullthrows.default)((await config.getConfigFrom(configItem.file.resolved, ['package.json'], {
247 parse: true
248 })));
249 config.addDevDependency(pkg.name, pkg.version);
250 }));
251}
252
253async function postDeserialize(config, options) {
254 let babelCore = config.result.internal ? bundledBabelCore : await options.packageManager.require('@babel/core', config.searchPath);
255 config.result.config.presets = await Promise.all(config.result.config.presets.map(async configItem => {
256 let value = await options.packageManager.require(configItem.file.resolved, config.searchPath);
257 value = value.default ? value.default : value;
258 return babelCore.createConfigItem([value, configItem.options], {
259 type: 'preset',
260 dirname: configItem.dirname
261 });
262 }));
263 config.result.config.plugins = await Promise.all(config.result.config.plugins.map(async configItem => {
264 let value = await options.packageManager.require(configItem.file.resolved, config.searchPath);
265 value = value.default ? value.default : value;
266 return babelCore.createConfigItem([value, configItem.options], {
267 type: 'plugin',
268 dirname: configItem.dirname
269 });
270 }));
271}
272
273async function reload(config, options) {
274 let {
275 loadPartialConfig
276 } = await loadBabelCore(config, options);
277 let partialConfig = loadPartialConfig({
278 filename: config.searchPath,
279 cwd: _path.default.dirname(config.searchPath),
280 root: options.projectRoot
281 });
282 config.setResult({
283 internal: false,
284 config: partialConfig.options,
285 targets: (0, _utils2.enginesToBabelTargets)(config.env)
286 });
287}
288
289function loadBabelCore(config, options) {
290 var _config$result;
291
292 return !config.isSource || ((_config$result = config.result) === null || _config$result === void 0 ? void 0 : _config$result.internal) ? bundledBabelCore : options.packageManager.require('@babel/core', config.searchPath);
293}
\No newline at end of file