UNPKG

9.3 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
5var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
6
7var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
8
9const URL = require('url');
10
11const path = require('path');
12
13const clone = require('clone');
14
15const fs = require('@parcel/fs');
16
17const md5 = require('./utils/md5');
18
19const isURL = require('./utils/is-url');
20
21const config = require('./utils/config');
22
23const syncPromise = require('./utils/syncPromise');
24
25const logger = require('@parcel/logger');
26
27const Resolver = require('./Resolver');
28
29const objectHash = require('./utils/objectHash');
30/**
31 * An Asset represents a file in the dependency tree. Assets can have multiple
32 * parents that depend on it, and can be added to multiple output bundles.
33 * The base Asset class doesn't do much by itself, but sets up an interface
34 * for subclasses to implement.
35 */
36
37
38class Asset {
39 constructor(name, options) {
40 this.id = null;
41 this.name = name;
42 this.basename = path.basename(this.name);
43 this.relativeName = path.relative(options.rootDir, this.name).replace(/\\/g, '/');
44 this.options = options;
45 this.encoding = 'utf8';
46 this.type = path.extname(this.name).slice(1);
47 this.hmrPageReload = false;
48 this.processed = false;
49 this.contents = options.rendition ? options.rendition.value : null;
50 this.ast = null;
51 this.generated = null;
52 this.hash = null;
53 this.sourceMaps = null;
54 this.parentDeps = new Set();
55 this.dependencies = new Map();
56 this.depAssets = new Map();
57 this.parentBundle = null;
58 this.bundles = new Set();
59 this.cacheData = {};
60 this.startTime = 0;
61 this.endTime = 0;
62 this.buildTime = 0;
63 this.bundledSize = 0;
64 this.resolver = new Resolver(options);
65 }
66
67 shouldInvalidate() {
68 return false;
69 }
70
71 loadIfNeeded() {
72 var _this = this;
73
74 return (0, _asyncToGenerator2.default)(function* () {
75 if (_this.contents == null) {
76 _this.contents = yield _this.load();
77 }
78 })();
79 }
80
81 parseIfNeeded() {
82 var _this2 = this;
83
84 return (0, _asyncToGenerator2.default)(function* () {
85 yield _this2.loadIfNeeded();
86
87 if (!_this2.ast) {
88 _this2.ast = yield _this2.parse(_this2.contents);
89 }
90 })();
91 }
92
93 getDependencies() {
94 var _this3 = this;
95
96 return (0, _asyncToGenerator2.default)(function* () {
97 if (_this3.options.rendition && _this3.options.rendition.hasDependencies === false) {
98 return;
99 }
100
101 yield _this3.loadIfNeeded();
102
103 if (_this3.contents && _this3.mightHaveDependencies()) {
104 yield _this3.parseIfNeeded();
105 yield _this3.collectDependencies();
106 }
107 })();
108 }
109
110 addDependency(name, opts) {
111 this.dependencies.set(name, Object.assign({
112 name
113 }, opts));
114 }
115
116 resolveDependency(url, from = this.name) {
117 const parsed = URL.parse(url);
118 let depName;
119 let resolved;
120 let dir = path.dirname(from);
121 const filename = decodeURIComponent(parsed.pathname);
122
123 if (filename[0] === '~' || filename[0] === '/') {
124 if (dir === '.') {
125 dir = this.options.rootDir;
126 }
127
128 depName = resolved = this.resolver.resolveFilename(filename, dir);
129 } else {
130 resolved = path.resolve(dir, filename);
131 depName = './' + path.relative(path.dirname(this.name), resolved);
132 }
133
134 return {
135 depName,
136 resolved
137 };
138 }
139
140 addURLDependency(url, from = this.name, opts) {
141 if (!url || isURL(url)) {
142 return url;
143 }
144
145 if (typeof from === 'object') {
146 opts = from;
147 from = this.name;
148 }
149
150 const _this$resolveDependen = this.resolveDependency(url, from),
151 depName = _this$resolveDependen.depName,
152 resolved = _this$resolveDependen.resolved;
153
154 this.addDependency(depName, Object.assign({
155 dynamic: true,
156 resolved
157 }, opts));
158 const parsed = URL.parse(url);
159 parsed.pathname = this.options.parser.getAsset(resolved, this.options).generateBundleName();
160 return URL.format(parsed);
161 }
162
163 get package() {
164 logger.warn('`asset.package` is deprecated. Please use `await asset.getPackage()` instead.');
165 return syncPromise(this.getPackage());
166 }
167
168 getPackage() {
169 var _this4 = this;
170
171 return (0, _asyncToGenerator2.default)(function* () {
172 if (!_this4._package) {
173 _this4._package = yield _this4.resolver.findPackage(path.dirname(_this4.name));
174 }
175
176 return _this4._package;
177 })();
178 }
179
180 getConfig(filenames, opts = {}) {
181 var _this5 = this;
182
183 return (0, _asyncToGenerator2.default)(function* () {
184 if (opts.packageKey) {
185 let pkg = yield _this5.getPackage();
186
187 if (pkg && pkg[opts.packageKey]) {
188 return clone(pkg[opts.packageKey]);
189 }
190 } // Resolve the config file
191
192
193 let conf = yield config.resolve(opts.path || _this5.name, filenames);
194
195 if (conf) {
196 // Add as a dependency so it is added to the watcher and invalidates
197 // this asset when the config changes.
198 _this5.addDependency(conf, {
199 includedInParent: true
200 });
201
202 if (opts.load === false) {
203 return conf;
204 }
205
206 return config.load(opts.path || _this5.name, filenames);
207 }
208
209 return null;
210 })();
211 }
212
213 mightHaveDependencies() {
214 return true;
215 }
216
217 load() {
218 var _this6 = this;
219
220 return (0, _asyncToGenerator2.default)(function* () {
221 return fs.readFile(_this6.name, _this6.encoding);
222 })();
223 }
224
225 parse() {// do nothing by default
226 }
227
228 collectDependencies() {// do nothing by default
229 }
230
231 pretransform() {// do nothing by default
232
233 return (0, _asyncToGenerator2.default)(function* () {})();
234 }
235
236 transform() {// do nothing by default
237
238 return (0, _asyncToGenerator2.default)(function* () {})();
239 }
240
241 generate() {
242 var _this7 = this;
243
244 return (0, _asyncToGenerator2.default)(function* () {
245 return {
246 [_this7.type]: _this7.contents
247 };
248 })();
249 }
250
251 process() {
252 var _this8 = this;
253
254 return (0, _asyncToGenerator2.default)(function* () {
255 // Generate the id for this asset, unless it has already been set.
256 // We do this here rather than in the constructor to avoid unnecessary work in the main process.
257 // In development, the id is just the relative path to the file, for easy debugging and performance.
258 // In production, we use a short hash of the relative path.
259 if (!_this8.id) {
260 _this8.id = _this8.options.production || _this8.options.scopeHoist ? md5(_this8.relativeName, 'base64').slice(0, 4) : _this8.relativeName;
261 }
262
263 if (!_this8.generated) {
264 yield _this8.loadIfNeeded();
265 yield _this8.pretransform();
266 yield _this8.getDependencies();
267 yield _this8.transform();
268 _this8.generated = yield _this8.generate();
269 }
270
271 return _this8.generated;
272 })();
273 }
274
275 postProcess(generated) {
276 return (0, _asyncToGenerator2.default)(function* () {
277 return generated;
278 })();
279 }
280
281 generateHash() {
282 return objectHash(this.generated);
283 }
284
285 invalidate() {
286 this.processed = false;
287 this.contents = null;
288 this.ast = null;
289 this.generated = null;
290 this.hash = null;
291 this.dependencies.clear();
292 this.depAssets.clear();
293 }
294
295 invalidateBundle() {
296 this.parentBundle = null;
297 this.bundles.clear();
298 this.parentDeps.clear();
299 }
300
301 generateBundleName() {
302 // Generate a unique name. This will be replaced with a nicer
303 // name later as part of content hashing.
304 return md5(this.relativeName) + '.' + this.type;
305 }
306
307 replaceBundleNames(bundleNameMap) {
308 let copied = false;
309
310 for (let key in this.generated) {
311 let value = this.generated[key];
312
313 if (typeof value === 'string') {
314 // Replace temporary bundle names in the output with the final content-hashed names.
315 let newValue = value;
316 var _iteratorNormalCompletion = true;
317 var _didIteratorError = false;
318 var _iteratorError = undefined;
319
320 try {
321 for (var _iterator = bundleNameMap[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
322 let _step$value = (0, _slicedToArray2.default)(_step.value, 2),
323 name = _step$value[0],
324 map = _step$value[1];
325
326 newValue = newValue.split(name).join(map);
327 } // Copy `this.generated` on write so we don't end up writing the final names to the cache.
328
329 } catch (err) {
330 _didIteratorError = true;
331 _iteratorError = err;
332 } finally {
333 try {
334 if (!_iteratorNormalCompletion && _iterator.return != null) {
335 _iterator.return();
336 }
337 } finally {
338 if (_didIteratorError) {
339 throw _iteratorError;
340 }
341 }
342 }
343
344 if (newValue !== value && !copied) {
345 this.generated = Object.assign({}, this.generated);
346 copied = true;
347 }
348
349 this.generated[key] = newValue;
350 }
351 }
352 }
353
354 generateErrorMessage(err) {
355 return err;
356 }
357
358}
359
360module.exports = Asset;
\No newline at end of file