UNPKG

guido

Version:

基于webpack4的一键式开发工具,集成handlebars、雪碧图、SVG Sprite、自定义资源注入等方式

306 lines (285 loc) 9.86 kB
'use strict'; const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); const safePostCssParser = require('postcss-safe-parser'); const autoprefixer = require('autoprefixer'); const postcssSprites = require('postcss-sprites'); const Typeof = require('../utils/typeof'); const env = require('../utils/env'); const isInlineResourceQuery = require('../utils/isInlineResourceQuery'); const appendModuleRule = require('../utils/appendModuleRule'); const sprites = require('../utils/postcssSprites'); const discernFontSVG = require('../utils/postcssDiscernFontSVG'); function isCSSFile(filePath) { return /\.css$/i.test(filePath) && !/\.module\.css$/i.test(filePath); } function isSCSSFile(filePath) { return ( /\.(scss|sass)$/i.test(filePath) && !/\.module\.(scss|sass)$/i.test(filePath) ); } function isCSSModulesFile(filePath) { return /\.modules\.css$/i.test(filePath); } function isSCSSModulesFile(filePath) { return /\.modules\.(scss|sass)$/i.test(filePath); } module.exports = function(config) { const RE_SPRITES_PATH = new RegExp( [config.output.imageDir.replace(/\//, '\\/'), '\\/(.*?)\\/.*'].join(''), 'i' ); const isProd = env.isProd(); const shouldUseSourceMap = !Typeof.isUndefined(config.devtool) && config.devtool !== false; // Module loader Config注入 // ==================== // style-loader的通用配置 let styleLoaderOptions = {}; // css-loader的通用配置 let cssLoaderOptionsForGeneral = { sourceMap: shouldUseSourceMap, importLoaders: 1, }; let cssLoaderOptionsForGeneralSCSS = Object.assign( {}, cssLoaderOptionsForGeneral ); cssLoaderOptionsForGeneralSCSS.importLoaders = 2; // css-loader的module css配置 let cssLoaderOptionsForModule = { modules: { mode: 'local', localIdentName: '[local]--[hash:base64:5]', }, importLoaders: 1, sourceMap: shouldUseSourceMap, }; let cssLoaderOptionsForModuleSCSS = Object.assign( {}, cssLoaderOptionsForModule ); cssLoaderOptionsForModuleSCSS.importLoaders = 2; // scss-loader的通用配置 let SCSSOptions = { sassOptions: { outputStyle: 'compressed', precision: 10, indentType: 'space', indentWidth: 2, sourceMap: shouldUseSourceMap, }, }; let autoprefixerOptions = {}; if (Typeof.isArray(config.browserslist)) { autoprefixerOptions.overrideBrowserslist = config.browserslist.slice(0); } let postCSSOptions = { // Necessary for external CSS imports to work // https://github.com/facebookincubator/create-react-app/issues/2677 ident: 'postcss', plugins: function() { return [ autoprefixer(autoprefixerOptions), postcssSprites({ verbose: false, retina: true, // 支持retina spritesmith: {}, filterBy: sprites.spritesFilterBy, groupBy: function(image) { return sprites.spritesGroupBy(RE_SPRITES_PATH, image); }, hooks: { // 更新生成后的规则,这里主要是改变了生成后的url访问路径 onUpdateRule: sprites.spritesOnUpdateRule, onSaveSpritesheet: sprites.spritesOnSaveSpritesheet, }, }), discernFontSVG(), ]; }, sourceMap: shouldUseSourceMap, }; config = appendModuleRule(config, [ { test: isCSSModulesFile, resourceQuery: isInlineResourceQuery, use: [ { loader: require.resolve('style-loader'), options: styleLoaderOptions, }, { loader: require.resolve('css-loader'), options: cssLoaderOptionsForModule, }, { loader: require.resolve('postcss-loader'), options: postCSSOptions, }, ], }, { test: isSCSSModulesFile, resourceQuery: isInlineResourceQuery, use: [ { loader: require.resolve('style-loader'), options: styleLoaderOptions, }, { loader: require.resolve('css-loader'), options: cssLoaderOptionsForModuleSCSS, }, { loader: require.resolve('postcss-loader'), options: postCSSOptions, }, { loader: require.resolve('sass-loader'), options: SCSSOptions, }, ], }, { test: isCSSFile, resourceQuery: isInlineResourceQuery, use: [ { loader: require.resolve('style-loader'), options: styleLoaderOptions, }, { loader: require.resolve('css-loader'), options: cssLoaderOptionsForGeneral, }, { loader: require.resolve('postcss-loader'), options: postCSSOptions, }, ], }, { test: isSCSSFile, resourceQuery: isInlineResourceQuery, use: [ { loader: require.resolve('style-loader'), options: styleLoaderOptions, }, { loader: require.resolve('css-loader'), options: cssLoaderOptionsForGeneralSCSS, }, { loader: require.resolve('postcss-loader'), options: postCSSOptions, }, { loader: require.resolve('sass-loader'), options: SCSSOptions, }, ], }, { test: isCSSModulesFile, use: [ MiniCssExtractPlugin.loader, { loader: require.resolve('css-loader'), options: cssLoaderOptionsForModule, }, { loader: require.resolve('postcss-loader'), options: postCSSOptions, }, ], }, { test: isSCSSModulesFile, use: [ MiniCssExtractPlugin.loader, { loader: require.resolve('css-loader'), options: cssLoaderOptionsForModuleSCSS, }, { loader: require.resolve('postcss-loader'), options: postCSSOptions, }, { loader: require.resolve('sass-loader'), options: SCSSOptions, }, ], }, { test: isCSSFile, use: [ MiniCssExtractPlugin.loader, { loader: require.resolve('css-loader'), options: cssLoaderOptionsForGeneral, }, { loader: require.resolve('postcss-loader'), options: postCSSOptions, }, ], }, { test: isSCSSFile, use: [ MiniCssExtractPlugin.loader, { loader: require.resolve('css-loader'), options: cssLoaderOptionsForGeneralSCSS, }, { loader: require.resolve('postcss-loader'), options: postCSSOptions, }, { loader: require.resolve('sass-loader'), options: SCSSOptions, }, ], }, ]); // 使用插件 optimize-css-assets-webpack-plugin原因: // 直接使用 minimize: true 在匹配到css后直接压缩 // 项目是用了autoprefix自动添加前缀,这样压缩,会导致添加的前缀丢失 config.optimization.minimizer.push( new OptimizeCSSAssetsPlugin({ cssProcessorOptions: { parser: safePostCssParser, map: shouldUseSourceMap ? { // `inline: false` forces the sourcemap to be output into a // separate file inline: false, // `annotation: true` appends the sourceMappingURL to the end of // the css file, helping the browser find the sourcemap annotation: true, } : false, }, }) ); config.plugins.push( new MiniCssExtractPlugin({ filename: path.join( config.output.cssDir, isProd ? '[name].[contenthash:8].css' : '[name].css' ), chunkFilename: path.join( config.output.cssDir, isProd ? '[name].chunk.[contenthash:8].css' : '[name].chunk.css' ), ignoreOrder: false, }) ); return config; };