@parcel/core
Version:
232 lines (229 loc) • 9.53 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = createWriteBundleRequest;
var _constants = require("../constants");
function _nullthrows() {
const data = _interopRequireDefault(require("nullthrows"));
_nullthrows = function () {
return data;
};
return data;
}
function _path() {
const data = _interopRequireDefault(require("path"));
_path = function () {
return data;
};
return data;
}
var _Bundle = require("../public/Bundle");
function _utils() {
const data = require("@parcel/utils");
_utils = function () {
return data;
};
return data;
}
function _stream() {
const data = require("stream");
_stream = function () {
return data;
};
return data;
}
var _projectPath = require("../projectPath");
var _ParcelConfigRequest = _interopRequireWildcard(require("./ParcelConfigRequest"));
var _PluginOptions = _interopRequireDefault(require("../public/PluginOptions"));
function _logger() {
const data = require("@parcel/logger");
_logger = function () {
return data;
};
return data;
}
var _DevDepRequest = require("./DevDepRequest");
var _ParcelConfig = _interopRequireDefault(require("../ParcelConfig"));
function _diagnostic() {
const data = _interopRequireWildcard(require("@parcel/diagnostic"));
_diagnostic = function () {
return data;
};
return data;
}
function _profiler() {
const data = require("@parcel/profiler");
_profiler = function () {
return data;
};
return data;
}
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && 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; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const BOUNDARY_LENGTH = _constants.HASH_REF_PREFIX.length + 32 - 1;
/**
* Writes a bundle to the dist directory, replacing hash references with the final content hashes.
*/
function createWriteBundleRequest(input) {
let name = (0, _nullthrows().default)(input.bundle.name);
let nameHash = (0, _nullthrows().default)(input.hashRefToNameHash.get(input.bundle.hashReference));
return {
id: `${input.bundle.id}:${input.info.hash}:${nameHash}:${name}`,
type: 'write_bundle_request',
run,
input
};
}
async function run({
input,
options,
api
}) {
var _info$time;
let {
bundleGraph,
bundle,
info,
hashRefToNameHash
} = input;
let {
inputFS,
outputFS
} = options;
let name = (0, _nullthrows().default)(bundle.name);
let thisHashReference = bundle.hashReference;
if (info.type !== bundle.type) {
name = name.slice(0, -_path().default.extname(name).length) + '.' + info.type;
}
if (name.includes(thisHashReference)) {
let thisNameHash = (0, _nullthrows().default)(hashRefToNameHash.get(thisHashReference));
name = name.replace(thisHashReference, thisNameHash);
}
let filePath = (0, _projectPath.joinProjectPath)(bundle.target.distDir, name);
// Watch the bundle and source map for deletion.
// Also watch the dist dir because invalidateOnFileDelete does not currently
// invalidate when a parent directory is deleted.
// TODO: do we want to also watch for file edits?
api.invalidateOnFileDelete(bundle.target.distDir);
api.invalidateOnFileDelete(filePath);
let cacheKeys = info.cacheKeys;
let mapKey = cacheKeys.map;
let fullPath = (0, _projectPath.fromProjectPath)(options.projectRoot, filePath);
if (mapKey && bundle.env.sourceMap && !bundle.env.sourceMap.inline) {
api.invalidateOnFileDelete((0, _projectPath.toProjectPath)(options.projectRoot, fullPath + '.map'));
}
let dir = _path().default.dirname(fullPath);
await outputFS.mkdirp(dir); // ? Got rid of dist exists, is this an expensive operation
// Use the file mode from the entry asset as the file mode for the bundle.
// Don't do this for browser builds, as the executable bit in particular is unnecessary.
let publicBundle = _Bundle.NamedBundle.get(bundle, bundleGraph, options);
let mainEntry = publicBundle.getMainEntry();
let writeOptions = publicBundle.env.isBrowser() || !mainEntry ? undefined : {
mode: (await inputFS.stat(mainEntry.filePath)).mode
};
let contentStream;
if (info.isLargeBlob) {
contentStream = options.cache.getStream(cacheKeys.content);
} else {
contentStream = (0, _utils().blobToStream)(await options.cache.getBlob(cacheKeys.content));
}
let size = 0;
contentStream = contentStream.pipe(new (_utils().TapStream)(buf => {
size += buf.length;
}));
let configResult = (0, _nullthrows().default)(await api.runRequest((0, _ParcelConfigRequest.default)()));
let config = (0, _ParcelConfigRequest.getCachedParcelConfig)(configResult, options);
let {
devDeps,
invalidDevDeps
} = await (0, _DevDepRequest.getDevDepRequests)(api);
(0, _DevDepRequest.invalidateDevDeps)(invalidDevDeps, options, config);
await writeFiles(contentStream, info, hashRefToNameHash, options, config, outputFS, filePath, writeOptions, devDeps, api);
if (mapKey && bundle.env.sourceMap && !bundle.env.sourceMap.inline && (await options.cache.has(mapKey))) {
await writeFiles((0, _utils().blobToStream)(await options.cache.getBlob(mapKey)), info, hashRefToNameHash, options, config, outputFS, (0, _projectPath.toProjectPathUnsafe)((0, _projectPath.fromProjectPathRelative)(filePath) + '.map'), writeOptions, devDeps, api);
}
let res = {
filePath,
type: info.type,
stats: {
size,
time: (_info$time = info.time) !== null && _info$time !== void 0 ? _info$time : 0
}
};
api.storeResult(res);
return res;
}
async function writeFiles(inputStream, info, hashRefToNameHash, options, config, outputFS, filePath, writeOptions, devDeps, api) {
let compressors = await config.getCompressors((0, _projectPath.fromProjectPathRelative)(filePath));
let fullPath = (0, _projectPath.fromProjectPath)(options.projectRoot, filePath);
let stream = info.hashReferences.length ? inputStream.pipe(replaceStream(hashRefToNameHash)) : inputStream;
let promises = [];
for (let compressor of compressors) {
promises.push(runCompressor(compressor, cloneStream(stream), options, outputFS, fullPath, writeOptions, devDeps, api));
}
await Promise.all(promises);
}
async function runCompressor(compressor, stream, options, outputFS, filePath, writeOptions, devDeps, api) {
let measurement;
try {
measurement = _profiler().tracer.createMeasurement(compressor.name, 'compress', _path().default.relative(options.projectRoot, filePath));
let res = await compressor.plugin.compress({
stream,
options: new _PluginOptions.default(options),
logger: new (_logger().PluginLogger)({
origin: compressor.name
}),
tracer: new (_profiler().PluginTracer)({
origin: compressor.name,
category: 'compress'
})
});
if (res != null) {
await new Promise((resolve, reject) => (0, _stream().pipeline)(res.stream, outputFS.createWriteStream(filePath + (res.type != null ? '.' + res.type : ''), writeOptions), err => {
if (err) reject(err);else resolve();
}));
}
} catch (err) {
throw new (_diagnostic().default)({
diagnostic: (0, _diagnostic().errorToDiagnostic)(err, {
origin: compressor.name
})
});
} finally {
measurement && measurement.end();
// Add dev deps for compressor plugins AFTER running them, to account for lazy require().
let devDepRequest = await (0, _DevDepRequest.createDevDependency)({
specifier: compressor.name,
resolveFrom: compressor.resolveFrom
}, devDeps, options);
await (0, _DevDepRequest.runDevDepRequest)(api, devDepRequest);
}
}
function replaceStream(hashRefToNameHash) {
let boundaryStr = '';
return new (_stream().Transform)({
transform(chunk, encoding, cb) {
let str = boundaryStr + chunk.toString();
let replaced = str.replace(_constants.HASH_REF_REGEX, match => {
return hashRefToNameHash.get(match) || match;
});
boundaryStr = replaced.slice(replaced.length - BOUNDARY_LENGTH);
let strUpToBoundary = replaced.slice(0, replaced.length - BOUNDARY_LENGTH);
cb(null, strUpToBoundary);
},
flush(cb) {
cb(null, boundaryStr);
}
});
}
function cloneStream(readable) {
let res = new (_stream().Readable)();
// $FlowFixMe
res._read = () => {};
readable.on('data', chunk => res.push(chunk));
readable.on('end', () => res.push(null));
readable.on('error', err => res.emit('error', err));
return res;
}