@regru/webpack-babel-multi-target-plugin
Version:
A Webpack plugin that works with Babel to allow deployment of ES2015 builds targeted to modern browsers, with an ES5 fallback for legacy browsers.
112 lines • 5.63 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const plugin_name_1 = require("./plugin.name");
const targeted_chunk_1 = require("./targeted.chunk");
// Works with HtmlWebpackPlugin to make sure the targeted assets are referenced correctly
// Tags for assets whose target has `esModule` set are updated with the `"type"="module"` attribute
// Tags for assets whose target has `noModule` set are updated with the `"nomodule"` attribute
/**
* @internalapi
*/
class BabelMultiTargetHtmlUpdater {
constructor(targets) {
this.targets = targets;
}
updateScriptTags(chunkMap, tags) {
tags
.forEach((tag) => {
if (tag.tagName !== 'script') {
return;
}
const targetedChunks = chunkMap.get(tag.attributes.src);
// chunks that are added outside of an entry point (e.g. by HtmlWebpackIncludeAssetsPlugin) will not be targeted
if (!targetedChunks) {
return;
}
const targets = targetedChunks.map(targetedChunk => targetedChunk.target);
if (!targets || !targets.length) {
return;
}
// if this file is referenced by multiple targets, don't change the tag
// this can happen with vendor chunks that don't get transpiled
if (!targets.every((target, index) => index === 0 || target === targets[index - 1])) {
return;
}
const target = targets[0];
if (target.esModule) {
tag.attributes.type = 'module';
return;
}
if (target.noModule) {
tag.attributes.nomodule = true;
}
});
}
// expands any provided chunk names (for options.chunks or options.excludeChunks) to include the targeted versions
// of each chunk. also includes the original chunk name if all targets are tagged so that CSS assets are included
// or excluded as expected
// also relevant: NormalizeCssChunks.extractCssChunks
mapChunkNames(chunkNames) {
const allTaggedWithKey = this.targets.every(target => target.tagAssetsWithKey);
return chunkNames.reduce((result, name) => {
if (allTaggedWithKey) {
result.push(name);
}
this.targets.forEach(target => {
result.push(target.getTargetedAssetName(name));
});
return result;
}, []);
}
apply(compiler) {
compiler.hooks.afterPlugins.tap(plugin_name_1.PLUGIN_NAME, () => {
const htmlWebpackPlugin = compiler.options.plugins
// instanceof can act wonky since we don't actually keep our own dependency on html-webpack-plugin
// should we?
.find(plugin => plugin.constructor.name === 'HtmlWebpackPlugin');
if (!htmlWebpackPlugin) {
return;
}
// not sure if this is a problem since webpack will wait for dependencies to load, but sorting
// by auto/dependency will result in a cyclic dependency error for lazy-loaded routes
htmlWebpackPlugin.options.chunksSortMode = 'none';
if (htmlWebpackPlugin.options.chunks !== 'all' &&
htmlWebpackPlugin.options.chunks &&
htmlWebpackPlugin.options.chunks.length) {
htmlWebpackPlugin.options.chunks = this.mapChunkNames(htmlWebpackPlugin.options.chunks);
}
if (htmlWebpackPlugin.options.excludeChunks &&
htmlWebpackPlugin.options.excludeChunks.length) {
htmlWebpackPlugin.options.excludeChunks = this.mapChunkNames(htmlWebpackPlugin.options.excludeChunks);
}
compiler.hooks.compilation.tap(plugin_name_1.PLUGIN_NAME, (compilation) => {
if (compilation.name) {
return;
}
compilation.hooks.htmlWebpackPluginAlterAssetTags.tapPromise(`${plugin_name_1.PLUGIN_NAME} update asset tags`, (htmlPluginData) => __awaiter(this, void 0, void 0, function* () {
const chunkMap = compilation.chunkGroups.reduce((result, chunkGroup) => {
chunkGroup.chunks.forEach((chunk) => {
chunk.files.forEach((file) => {
result.set(file, chunkGroup, chunk);
});
});
return result;
}, new targeted_chunk_1.TargetedChunkMap(compiler.options.output.publicPath));
this.updateScriptTags(chunkMap, htmlPluginData.head);
this.updateScriptTags(chunkMap, htmlPluginData.body);
return htmlPluginData;
}));
});
});
}
}
exports.BabelMultiTargetHtmlUpdater = BabelMultiTargetHtmlUpdater;
//# sourceMappingURL=babel.multi.target.html.updater.js.map