@tarojs/webpack-runner
Version:
webpack runner for taro
453 lines • 18.3 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
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) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDevtool = exports.getOutput = exports.parseModule = exports.getMainPlugin = exports.getCopyWebpackPlugin = exports.getCssoWebpackPlugin = exports.getTerserPlugin = exports.getHotModuleReplacementPlugin = exports.getDefinePlugin = exports.getHtmlWebpackPlugin = exports.getMiniCssExtractPlugin = exports.processEnvOption = exports.makeConfig = void 0;
const helper_1 = require("@tarojs/helper");
const runner_utils_1 = require("@tarojs/runner-utils");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const csso_webpack_plugin_1 = require("csso-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const lodash_1 = require("lodash");
const fp_1 = require("lodash/fp");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require("path");
const sass = require("sass");
const TerserPlugin = require("terser-webpack-plugin");
const webpack = require("webpack");
const postcss_conf_1 = require("../config/postcss.conf");
const H5Plugin_1 = require("../plugins/H5Plugin");
const makeConfig = (buildConfig) => __awaiter(void 0, void 0, void 0, function* () {
const sassLoaderOption = yield (0, runner_utils_1.getSassLoaderOption)(buildConfig);
return Object.assign(Object.assign({}, buildConfig), { sassLoaderOption });
});
exports.makeConfig = makeConfig;
const defaultTerserOption = {
keep_fnames: true,
output: {
comments: false,
keep_quoted_props: true,
quote_keys: true,
beautify: false
},
warnings: false
};
const defaultCSSCompressOption = {
mergeRules: false,
mergeIdents: false,
reduceIdents: false,
discardUnused: false,
minifySelectors: false
};
const defaultMediaUrlLoaderOption = {
limit: 10240,
esModule: false
};
const defaultFontUrlLoaderOption = {
limit: 10240,
esModule: false
};
const defaultImageUrlLoaderOption = {
limit: 10240,
esModule: false
};
const defaultCssModuleOption = {
enable: false,
config: {
namingPattern: 'global',
generateScopedName: '[name]__[local]___[hash:base64:5]'
}
};
const getLoader = (loaderName, options) => {
return {
loader: require.resolve(loaderName),
options: options || {}
};
};
const listify = listOrItem => {
if (Array.isArray(listOrItem)) {
return listOrItem;
}
return [listOrItem];
};
const getPlugin = (plugin, args) => {
return {
plugin,
args
};
};
const mergeOption = ([...options]) => {
return (0, helper_1.recursiveMerge)({}, ...options);
};
exports.processEnvOption = (0, lodash_1.partial)(fp_1.mapKeys, key => `process.env.${key}`);
const getStyleLoader = (0, fp_1.pipe)(mergeOption, (0, lodash_1.partial)(getLoader, 'style-loader'));
const getCssLoader = (0, fp_1.pipe)(mergeOption, (0, lodash_1.partial)(getLoader, 'css-loader'));
const getPostcssLoader = (0, fp_1.pipe)(mergeOption, (0, lodash_1.partial)(getLoader, 'postcss-loader'));
const getResolveUrlLoader = (0, fp_1.pipe)(mergeOption, (0, lodash_1.partial)(getLoader, 'resolve-url-loader'));
const getSassLoader = (0, fp_1.pipe)(mergeOption, (0, lodash_1.partial)(getLoader, 'sass-loader'));
const getLessLoader = (0, fp_1.pipe)(mergeOption, (0, lodash_1.partial)(getLoader, 'less-loader'));
const getStylusLoader = (0, fp_1.pipe)(mergeOption, (0, lodash_1.partial)(getLoader, 'stylus-loader'));
const getBabelLoader = (0, fp_1.pipe)(mergeOption, (0, lodash_1.partial)(getLoader, 'babel-loader'));
const getUrlLoader = (0, fp_1.pipe)(mergeOption, (0, lodash_1.partial)(getLoader, 'url-loader'));
const getExtractCssLoader = () => {
return {
loader: MiniCssExtractPlugin.loader
};
};
const getImportMetaLoader = (0, fp_1.pipe)(mergeOption, (0, lodash_1.partial)(getLoader, '@open-wc/webpack-import-meta-loader'));
exports.getMiniCssExtractPlugin = (0, fp_1.pipe)(mergeOption, listify, (0, lodash_1.partial)(getPlugin, MiniCssExtractPlugin));
exports.getHtmlWebpackPlugin = (0, fp_1.pipe)(mergeOption, listify, (0, lodash_1.partial)(getPlugin, HtmlWebpackPlugin));
exports.getDefinePlugin = (0, fp_1.pipe)(mergeOption, listify, (0, lodash_1.partial)(getPlugin, webpack.DefinePlugin));
exports.getHotModuleReplacementPlugin = (0, lodash_1.partial)(getPlugin, webpack.HotModuleReplacementPlugin, []);
const getTerserPlugin = ([enableSourceMap, terserOptions]) => {
return new TerserPlugin({
cache: true,
parallel: true,
sourceMap: enableSourceMap,
terserOptions: (0, helper_1.recursiveMerge)({}, defaultTerserOption, terserOptions)
});
};
exports.getTerserPlugin = getTerserPlugin;
const getCssoWebpackPlugin = ([cssoOption]) => {
return (0, fp_1.pipe)(mergeOption, listify, (0, lodash_1.partial)(getPlugin, csso_webpack_plugin_1.default))([defaultCSSCompressOption, cssoOption]);
};
exports.getCssoWebpackPlugin = getCssoWebpackPlugin;
const getCopyWebpackPlugin = ({ copy, appPath }) => {
const args = [
copy.patterns.map((_a) => {
var { from, to } = _a, extra = __rest(_a, ["from", "to"]);
return Object.assign({ from, to: path.resolve(appPath, to), context: appPath }, extra);
}),
copy.options
];
return (0, lodash_1.partial)(getPlugin, CopyWebpackPlugin)(args);
};
exports.getCopyWebpackPlugin = getCopyWebpackPlugin;
const getMainPlugin = args => {
return (0, lodash_1.partial)(getPlugin, H5Plugin_1.default)([args]);
};
exports.getMainPlugin = getMainPlugin;
const styleModuleReg = /(.*\.module).*\.(css|s[ac]ss|less|styl)\b/;
const styleGlobalReg = /(.*\.global).*\.(css|s[ac]ss|less|styl)\b/;
const isNodeModule = (filename) => /\bnode_modules\b/.test(filename);
const taroModuleRegs = [/@tarojs[/\\_]components/, /\btaro-components\b/];
const isTaroModule = (filename) => taroModuleRegs.some(reg => reg.test(filename));
const defaultEsnextModuleRegs = [
/@tarojs[/\\_]components/,
/\btaro-components\b/,
/@tarojs[/\\_]taro-h5/,
/\btaro-h5\b/,
/@tarojs[/\\_]router/,
/\btaro-router\b/,
/@tarojs[/\\_]redux-h5/,
/\btaro-redux-h5\b/,
/@tarojs[/\\_]mobx-h5/,
/\btaro-mobx-h5\b/
];
const getEsnextModuleRules = esnextModules => {
return [...defaultEsnextModuleRegs, ...esnextModules];
};
const parseModule = (appPath, { designWidth, deviceRatio, enableExtract, enableSourceMap, styleLoaderOption, cssLoaderOption, lessLoaderOption, sassLoaderOption, stylusLoaderOption, fontUrlLoaderOption, imageUrlLoaderOption, mediaUrlLoaderOption, esnextModules = [], compile, postcss, sourceDir, staticDirectory }) => {
const customPostcssOption = postcss || {};
const defaultStyleLoaderOption = {
/**
* 移除singleton设置,会导致样式库优先级发生错误
* singleton: true
*/
};
const cssModuleOptions = (0, helper_1.recursiveMerge)({}, defaultCssModuleOption, customPostcssOption.cssModules);
const { namingPattern, generateScopedName } = cssModuleOptions.config;
const cssOptions = [
{
importLoaders: 1,
sourceMap: enableSourceMap,
modules: false
},
cssLoaderOption
];
const cssOptionsWithModule = [
Object.assign({
importLoaders: 1,
sourceMap: enableSourceMap,
modules: {
mode: namingPattern === 'module' ? 'local' : 'global'
}
}, {
modules: typeof generateScopedName === 'function'
? { getLocalIdent: (context, _, localName) => generateScopedName(localName, context.resourcePath) }
: { localIdentName: generateScopedName }
}),
cssLoaderOption
];
const esnextModuleRules = getEsnextModuleRules(esnextModules);
/**
* isEsnextModule
*
* 使用正则匹配判断是否是es模块
* 规则参考:https://github.com/webpack/webpack/blob/master/lib/RuleSet.js#L413
*/
const isEsnextModule = (filename) => esnextModuleRules.some(pattern => {
if (pattern instanceof RegExp) {
return pattern.test(filename);
}
else {
return filename.indexOf(pattern) > -1;
}
});
const styleLoader = getStyleLoader([defaultStyleLoaderOption, styleLoaderOption]);
const topStyleLoader = getStyleLoader([defaultStyleLoaderOption, {
insert: function insertAtTop(element) {
// eslint-disable-next-line no-var
var parent = document.querySelector('head');
if (parent) {
// eslint-disable-next-line no-var
var lastInsertedElement = window._lastElementInsertedByStyleLoader;
if (!lastInsertedElement) {
parent.insertBefore(element, parent.firstChild);
}
else if (lastInsertedElement.nextSibling) {
parent.insertBefore(element, lastInsertedElement.nextSibling);
}
else {
parent.appendChild(element);
}
window._lastElementInsertedByStyleLoader = element;
}
}
}, styleLoaderOption]);
const extractCssLoader = getExtractCssLoader();
const lastStyleLoader = enableExtract ? extractCssLoader : styleLoader;
/**
* css-loader 1.0.0版本移除了minimize选项...升级需谨慎
*
* https://github.com/webpack-contrib/css-loader/releases/tag/v1.0.0
*/
const cssLoader = getCssLoader(cssOptions);
const cssLoaders = [
{
use: [cssLoader]
}
];
if (cssModuleOptions.enable) {
const cssLoaderWithModule = getCssLoader(cssOptionsWithModule);
let cssModuleCondition;
if (cssModuleOptions.config.namingPattern === 'module') {
/* 不排除 node_modules 内的样式 */
cssModuleCondition = styleModuleReg;
// for vue
cssLoaders.unshift({
resourceQuery: /module=/,
use: [cssLoaderWithModule]
});
}
else {
cssModuleCondition = {
and: [{ exclude: styleGlobalReg }, { exclude: [isNodeModule] }]
};
}
cssLoaders.unshift({
include: [cssModuleCondition],
use: [cssLoaderWithModule]
});
}
const postcssOption = (0, postcss_conf_1.getDefaultPostcssConfig)({
designWidth,
deviceRatio,
option: customPostcssOption
});
const postcssLoader = getPostcssLoader([
{ sourceMap: enableSourceMap },
{
postcssOptions: {
plugins: (0, postcss_conf_1.getPostcssPlugins)(appPath, postcssOption)
}
}
]);
const resolveUrlLoader = getResolveUrlLoader([{}]);
const baseSassOptions = {
sourceMap: true,
implementation: sass,
sassOptions: {
outputStyle: 'expanded',
fiber: false,
importer(url, prev, done) {
// 让 sass 文件里的 @import 能解析小程序原生样式文体,如 @import "a.wxss";
const extname = path.extname(url);
// fix: @import 文件可以不带scss/sass缀,如: @import "define";
if (extname === '.scss' || extname === '.sass' || extname === '.css' || !extname) {
return null;
}
else {
const filePath = path.resolve(path.dirname(prev), url);
helper_1.fs.access(filePath, helper_1.fs.constants.F_OK, (err) => {
if (err) {
console.log(err);
return null;
}
else {
helper_1.fs.readFile(filePath)
.then(res => {
done({ contents: res.toString() });
})
.catch(err => {
console.log(err);
return null;
});
}
});
}
}
}
};
const sassLoader = getSassLoader([baseSassOptions, {
sassOptions: {
indentedSyntax: true
}
}, sassLoaderOption]);
const scssLoader = getSassLoader([baseSassOptions, sassLoaderOption]);
const lessLoader = getLessLoader([{ sourceMap: enableSourceMap }, lessLoaderOption]);
const stylusLoader = getStylusLoader([{ sourceMap: enableSourceMap }, stylusLoaderOption]);
const scriptRule = {
test: helper_1.REG_SCRIPTS,
use: {
babelLoader: getBabelLoader([{
compact: false
}]),
/** stencil 2.14 开始使用了 import.meta.url 需要额外处理
* https://github.com/webpack/webpack/issues/6719
*/
importMeta: getImportMetaLoader([]),
}
};
if (compile.exclude && compile.exclude.length) {
scriptRule.exclude = [
...compile.exclude,
filename => /css-loader/.test(filename) || (/node_modules/.test(filename) && !(/taro/.test(filename)))
];
}
else if (compile.include && compile.include.length) {
scriptRule.include = [
...compile.include,
sourceDir,
filename => /taro/.test(filename)
];
}
else {
/**
* 要优先处理 css-loader 问题
*
* https://github.com/webpack-contrib/mini-css-extract-plugin/issues/471#issuecomment-750266195
*
* 若包含 @tarojs/components,则跳过 babel-loader 处理
* 除了包含 taro 和 inversify 的第三方依赖均不经过 babel-loader 处理
*/
scriptRule.exclude = [filename => /css-loader/.test(filename)
// || /@tarojs[\\/]components/.test(filename) Note: stencil 2.14 开始使用了 import.meta.url 需要额外处理
|| (/node_modules/.test(filename) && !(/taro/.test(filename) || /inversify/.test(filename)))];
}
const rule = {};
rule.taroStyle = {
test: helper_1.REG_STYLE,
use: [topStyleLoader],
include: [(filename) => isTaroModule(filename)]
};
rule.customStyle = {
test: helper_1.REG_STYLE,
use: [lastStyleLoader],
exclude: [(filename) => isTaroModule(filename)]
};
rule.css = {
test: helper_1.REG_STYLE,
oneOf: cssLoaders
};
rule.postcss = {
test: helper_1.REG_STYLE,
use: [postcssLoader],
exclude: [
filename => {
if (isTaroModule(filename)) {
return true;
}
else if (isEsnextModule(filename)) {
return false;
}
else {
return isNodeModule(filename);
}
}
]
};
rule.sass = {
test: helper_1.REG_SASS_SASS,
use: [resolveUrlLoader, sassLoader]
};
rule.scss = {
test: helper_1.REG_SASS_SCSS,
use: [resolveUrlLoader, scssLoader]
};
rule.less = {
test: helper_1.REG_LESS,
use: [lessLoader]
};
rule.stylus = {
test: helper_1.REG_STYLUS,
use: [stylusLoader]
};
rule.script = scriptRule;
rule.media = {
test: helper_1.REG_MEDIA,
use: {
urlLoader: getUrlLoader([
defaultMediaUrlLoaderOption,
Object.assign({ name: `${staticDirectory}/media/[name].[ext]` }, mediaUrlLoaderOption)
])
}
};
rule.font = {
test: helper_1.REG_FONT,
use: {
urlLoader: getUrlLoader([
defaultFontUrlLoaderOption,
Object.assign({ name: `${staticDirectory}/fonts/[name].[ext]` }, fontUrlLoaderOption)
])
}
};
rule.image = {
test: helper_1.REG_IMAGE,
use: {
urlLoader: getUrlLoader([
defaultImageUrlLoaderOption,
Object.assign({ name: `${staticDirectory}/images/[name].[ext]` }, imageUrlLoaderOption)
])
}
};
return { rule, postcssOption };
};
exports.parseModule = parseModule;
const getOutput = (appPath, [{ outputRoot, publicPath, chunkDirectory }, customOutput]) => {
return Object.assign({ path: path.resolve(appPath, outputRoot), filename: 'js/[name].js', chunkFilename: `${chunkDirectory}/[name].js`, publicPath }, customOutput);
};
exports.getOutput = getOutput;
const getDevtool = ({ enableSourceMap, sourceMapType = 'cheap-module-eval-source-map' }) => {
return enableSourceMap ? sourceMapType : 'none';
};
exports.getDevtool = getDevtool;
//# sourceMappingURL=chain.js.map
;