UNPKG

@tarojs/webpack-runner

Version:

webpack runner for taro

453 lines 18.3 kB
"use strict"; 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