@loadable/babel-plugin
Version:
Babel plugin for loadable (required for SSR).
171 lines (136 loc) • 5.99 kB
JavaScript
;
exports.__esModule = true;
exports.default = chunkNameProperty;
var _vm = _interopRequireDefault(require("vm"));
var _util = require("../util");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
const JS_PATH_REGEXP = /^[./]+|(\.js$)/g;
const MATCH_LEFT_HYPHENS_REPLACE_REGEX = /^-/g; // https://github.com/webpack/webpack/blob/master/lib/Template.js
const WEBPACK_CHUNK_NAME_REGEXP = /webpackChunkName/;
const WEBPACK_PATH_NAME_NORMALIZE_REPLACE_REGEX = /[^a-zA-Z0-9_!§$()=\-^°]+/g;
const WEBPACK_MATCH_PADDED_HYPHENS_REPLACE_REGEX = /^-|-$/g;
function readWebpackCommentValues(str) {
try {
const values = _vm.default.runInNewContext(`(function(){return {${str}};})()`);
return values;
} catch (e) {
throw Error(`compilation error while processing: /*${str}*/: ${e.message}`);
}
}
function writeWebpackCommentValues(values) {
try {
const str = Object.keys(values).map(key => `${key}: ${JSON.stringify(values[key])}`).join(', ');
return ` ${str} `;
} catch (e) {
throw Error(`compilation error while processing: /*${values}*/: ${e.message}`);
}
}
function getChunkNameComment(importArg) {
if (!importArg.has('leadingComments')) return null;
return importArg.get('leadingComments').find(comment => comment.node.value.match(WEBPACK_CHUNK_NAME_REGEXP));
}
function getRawChunkNameFromCommments(importArg) {
const chunkNameComment = getChunkNameComment(importArg);
if (!chunkNameComment) return null;
return readWebpackCommentValues(chunkNameComment.node.value);
}
function moduleToChunk(str) {
if (typeof str !== 'string') return '';
return str.replace(JS_PATH_REGEXP, '').replace(WEBPACK_PATH_NAME_NORMALIZE_REPLACE_REGEX, '-').replace(WEBPACK_MATCH_PADDED_HYPHENS_REPLACE_REGEX, '');
}
function replaceQuasi(str, stripLeftHyphen) {
if (!str) return '';
const result = str.replace(WEBPACK_PATH_NAME_NORMALIZE_REPLACE_REGEX, '-');
if (!stripLeftHyphen) return result;
return result.replace(MATCH_LEFT_HYPHENS_REPLACE_REGEX, '');
}
function chunkNameProperty({
types: t
}) {
function transformQuasi(quasi, first, single) {
return t.templateElement({
raw: single ? moduleToChunk(quasi.value.raw) : replaceQuasi(quasi.value.raw, first),
cooked: single ? moduleToChunk(quasi.value.cooked) : replaceQuasi(quasi.value.cooked, first)
}, quasi.tail);
}
function sanitizeChunkNameTemplateLiteral(node) {
return t.callExpression(t.memberExpression(node, t.identifier('replace')), [t.regExpLiteral(WEBPACK_PATH_NAME_NORMALIZE_REPLACE_REGEX.source, 'g'), t.stringLiteral('-')]);
}
function combineExpressions(node) {
const {
expressions
} = node;
const {
length
} = expressions;
if (length === 1) {
return expressions[0];
}
return expressions.slice(1).reduce((r, p) => t.binaryExpression('+', r, p), expressions[0]);
}
function generateChunkNameNode(callPath, prefix) {
const importArg = (0, _util.getImportArg)(callPath);
if (importArg.isTemplateLiteral()) {
return prefix ? t.binaryExpression('+', t.stringLiteral(prefix), sanitizeChunkNameTemplateLiteral(combineExpressions(importArg.node))) : t.templateLiteral(importArg.node.quasis.map((quasi, index) => transformQuasi(quasi, index === 0, importArg.node.quasis.length === 1)), importArg.node.expressions);
}
return t.stringLiteral(moduleToChunk(importArg.node.value));
}
function getExistingChunkNameComment(callPath) {
const importArg = (0, _util.getImportArg)(callPath);
const values = getRawChunkNameFromCommments(importArg);
return values;
}
function isAgressiveImport(callPath) {
const importArg = (0, _util.getImportArg)(callPath);
return importArg.isTemplateLiteral() && importArg.node.expressions.length > 0;
}
function addOrReplaceChunkNameComment(callPath, values) {
const importArg = (0, _util.getImportArg)(callPath);
const chunkNameComment = getChunkNameComment(importArg);
if (chunkNameComment) {
chunkNameComment.remove();
}
importArg.addComment('leading', writeWebpackCommentValues(values));
}
function chunkNameFromTemplateLiteral(node) {
const [q1] = node.quasis;
const v1 = q1 ? q1.value.cooked : '';
if (!node.expressions.length) return v1;
return `${v1}[request]`;
}
function getChunkNamePrefix(chunkName) {
if (typeof chunkName !== 'string') return '';
const match = chunkName.match(/(.+?)\[(request|index)\]$/);
return match ? match[1] : '';
}
function replaceChunkName(callPath) {
const agressiveImport = isAgressiveImport(callPath);
const values = getExistingChunkNameComment(callPath);
let {
webpackChunkName
} = values || {};
if (!agressiveImport && values) {
addOrReplaceChunkNameComment(callPath, values);
return t.stringLiteral(webpackChunkName);
}
let chunkNameNode = generateChunkNameNode(callPath, getChunkNamePrefix(webpackChunkName));
if (t.isTemplateLiteral(chunkNameNode)) {
webpackChunkName = chunkNameFromTemplateLiteral(chunkNameNode);
chunkNameNode = sanitizeChunkNameTemplateLiteral(chunkNameNode);
} else if (t.isStringLiteral(chunkNameNode)) {
webpackChunkName = chunkNameNode.value;
}
addOrReplaceChunkNameComment(callPath, _extends({}, values, {
webpackChunkName
}));
return chunkNameNode;
}
return ({
callPath,
funcPath
}) => {
const chunkName = replaceChunkName(callPath);
return t.objectMethod('method', t.identifier('chunkName'), funcPath.node.params, t.blockStatement([t.returnStatement(chunkName)]));
};
}