webpack 配置从头到脚

下面是webpack.conf.prod.js 部分内容

const path = require("path");
const config = {
  mode: "production",
  resolve: webpackConfigResolve,
  stats: "minimal",
  entry: './app.js';
  output: {
    filename:'bundle.js',
  },
  module: {
    rules: webpackConfigmModuleRules,
  },
  optimization: {},
  plugins: [],
};

首先认识下webpack每项配置项

entry

待更

output

待更

module

待更

resolve

webpack 在启动后会从配置的入口模块出发找出所有依赖的模块,resolve配置 webpack 如何寻找模块所对应的文件。 webpack 内置 JavaScript 模块化语法解析功能,默认会采用模块化标准里约定好的规则去寻找,但你也可以根据自己的需要修改默认的规则。如下配置

const path = require('path');
function resolve(dir) {
  return path.join(__dirname, '..', dir);
}
module.exports = {
  extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.less', '.css'],
  mainFields: ['module', 'jsnext:main', 'main'],
  symlinks: false,
  alias: {
    '@': resolve('src'),
  },
};
  • alias
    resolve.alias配置项通过别名来把原导入路径映射成一个新的导入路径。例如使用以下配置:
 resolve:{
  alias:{
    components: './src/components/'
  }
}

当你通过import Button from 'components/button导入时,实际上被 alias 等价替换成了 import Button from './src/components/button'

以上 alias 配置的含义是把导入语句里的components关键字替换成./src/components/

这样做可能会命中太多的导入语句,alias 还支持 $ 符号来缩小范围到只命中以关键字结尾的导入语句:

resolve:{
  alias:{
    'react$': '/path/to/react.min.js'
  }
}

react$只会命中以react结尾的导入语句,即只会把import 'react'关键字替换成import '/path/to/react.min.js'

  • mainFields
    有一些第三方模块会针对不同环境提供几分代码。 例如分别提供采用 ES5 和 ES6 的2份代码,这2份代码的位置写在package.json文件里,如下:
{
  "jsnext:main": "es/index.js",// 采用 ES6 语法的代码入口文件
  "main": "lib/index.js" // 采用 ES5 语法的代码入口文件
}

Webpack 会根据 mainFields 的配置去决定优先采用那份代码, mainFields 默认如下:

mainFields: ['browser', 'main']

Webpack 会按照数组里的顺序去 package.json 文件里寻找,只会使用找到的第一个
假如你想优先采用 ES6 的那份代码,可以这样配置:

mainFields: ['jsnext:main', 'browser', 'main']
  • extensions
    在导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试访问文件是否存在。resolve.extensions用于配置在尝试过程中用到的后缀列表,默认是:
extensions: ['.js', '.json']

也就是说当遇到require('./data')这样的导入语句时,Webpack 会先去寻找./data.js文件,如果该文件不存在就去寻找./data.json文件, 如果还是找不到就报错。

假如你想让 Webpack 优先使用目录下的 TypeScript 文件,可以这样配置:

extensions: ['.ts', '.js', '.json']
  • modules
    resolve.modules 配置 Webpack 去哪些目录下寻找第三方模块,默认是只会去 node_modules 目录下寻找。 有时你的项目里会有一些模块会大量被其它模块依赖和导入,由于其它模块的位置分布不定,针对不同的文件都要去计算被导入模块文件的相对路径, 这个路径有时候会很长,就像这样 import ../../../components/button' 这时你可以利用modules配置项优化,假如那些被大量导入的模块都在./src/components目录下,把 modules 配置成
modules:['./src/components','node_modules']

后,你可以简单通过import 'button'导入。

  • descriptionFiles
    resolve.descriptionFiles配置描述第三方模块的文件名称,也就是 package.json 文件。默认如下:
descriptionFiles: ['package.json']
  • enforceExtension
    resolve.enforceExtension如果配置为true所有导入语句都必须要带文件后缀,例如开启前import './foo'能正常工作,开启后就必须写成import './foo.js'

  • enforceModuleExtension
    enforceModuleExtensionenforceExtension 作用类似,但 enforceModuleExtension 只对 node_modules 下的模块生效。 enforceModuleExtension 通常搭配 enforceExtension 使用,在 enforceExtension:true 时,因为安装的第三方模块中大多数导入语句没带文件后缀, 所以这时通过配置 enforceModuleExtension:false 来兼容第三方模块

plugins

常用的plugins如下

const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const cssnano = require("cssnano");
const TerserPlugin = require("terser-webpack-plugin");
const HappyPack = require("happypack");
  • html-webpack-plugin
    作用:生成html
const htmlPlugin = new HtmlWebpackPlugin({
    filename: `${entry}.html`,
    title: `${titles[entry]}`,
    template: path.resolve(__dirname, '../../src/index.js'),
    chunks: [
      'vendors.core',
      'vendors.commons',
    ],
    minify: HtmlWebpackPluginMinifyOptions,
  });

html-webpack-plugin插件详细用法参见:
//www.greatytc.com/p/08a60756ffda

  • HotModuleReplacementPlugin
    作用:页面热更新(模块热替换)
    首先我们要确保项目是基于webpack-dev-serverwebpack-dev-middle进行开发的,webpack本身的命令行并不支持HMR。webpack.conf.dev.js文件部分内容如下:
const webpack = require('webpack');
module.exports = {
  // ...
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ],
  devServer:{
    hot:true,
  }
}

也可以在页面中开启HMR,比如下面这个例子:

import { add } from 'util.js';
add(2,3);
if(module.hot){
  module.hot.accept();
}

热更新原理:
css-loader、vue-loader已经帮我们写了这部分代码,所以不需要手写了,但是如果是HTML,需要自己手动执行下面的代码

if (module.hot) {
  module.hot.accept('文件地址', () => {
    // 重新执行文件
  })
}
  • mini-css-extract-plugin(webpack 4及以上版本)
    mini-css-extract-plugin可以理解成extract-text-webpack-plugin的升级版,它拥有更丰富的特性和更好的性能,从Webpack 4开始官方推荐使用该插件进行样式提取(Webpack 4以前的版本是用不了的)。
    说到mini-css-extract-plugin的特性,最重要的就是它支持按需加载CSS,以前在使用extract-text-webpack-plugin的时候我们是做不到这一点的。举个例子,a.js通过import()函数异步加载了b.js,b.js里面加载了style.css,那么style.css最终只能被同步加载(通过HTML的link标签)。但是现在mini-css-extract-plugin会单独打包出一个0.css(假设使用默认配置),这个CSS文件将由a.js通过动态插入link标签的方式加载。

在webpack.conf.prod.js中引入:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
    entry: './app.js',
    output: {
        filename:'[name].js',
    },
    mode: 'development',
    module: {
        rules: [{
            test: /\.css$/,
            use: [
                {
                    loader: MiniCssExtractPlugin.loader,
                    options: {
                        publicPath:'../',
                    },
                },
                'css-loader'
            ],
        }],
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: '[name].css',
            chunkFilename:'[name].css',
        })
    ]
}
  • extract-text-webpack-plugin(webpack 4之前版本)
    作用:提取样式到css文件
    在webpack.conf.prod.js中引入:
const ExtractTextplugin = require('extract-text-webpack-plugin');
module.exports = {
  entry: './app.js';
  output: {
    filename:'bundle.js',
  },
  mode:'development',
  module: {
    rules:[
      {
        test:/\.css$/,
        use:ExtractTextplugin.extract({
          fallback:'style-loader',
          use:'css-loader',
        })
      }
    ]
  },
  plugins:[
    new ExtractTextPlugin('bundle.css')
  ]
} 
  • optimize-css-assets-webpack-plugin
    作用:压缩css
    压缩CSS文件的前提是使用extract-text-webpack-plugin或mini-css-extract-plugin将样式提取出来,接着使用optimize-css-assets-webpack-plugin来进行压缩,这个插件本质上使用的是压缩器cssnano,当然我们也可以通过其配置进行切换。具体请看下面的例子:
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: 'css-loader',
                }),
            }
        ],
    },
    plugins: [new ExtractTextPlugin('style.css')],
    optimization: {
        minimizer: [new OptimizeCSSAssetsPlugin({
            // 生效范围,只压缩匹配到的资源
            assetNameRegExp: /\.optimize\.css$/g,
            // 压缩处理器,默认为 cssnano
            cssProcessor: require('cssnano'),
            // 压缩处理器的配置
            cssProcessorOptions: { discardComments: { removeAll: true } },
            // 是否展示 log
            canPrint: true,
        })],
    },
};
  • terser-webpack-plugin (webpack 4 集成)
    作用:压缩Javascript
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
    //...
    optimization: {
        // 覆盖默认的 minimizer
        minimizer: [
            new TerserPlugin({
                /* your config */
                test: /\.js(\?.*)?$/i,
                exclude: /\/excludes/,
            })
        ],
    },
};
  • webpack-bundle-analyzer
    作用:分析打包后输出的bundle体积大小。
    配置如下:
const Analyzer = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
  ...
  plugins: [
    new Analyzer()
    ],
}
  • clean-webpack-plugin
    作用:在每次构建前清理 /dist 文件夹。
    配置如下:
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
  ...
  plugins:[
        new CleanWebpackPlugin()
  ],
}

参考博客:
https://www.cnblogs.com/joyco773/p/9049760.html
//www.greatytc.com/p/755aad97d810
//www.greatytc.com/p/2df87e8f4d3e
//www.greatytc.com/p/d08d5bc85ad2

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,639评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,277评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,221评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,474评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,570评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,816评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,957评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,718评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,176评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,511评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,646评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,322评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,934评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,755评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,987评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,358评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,514评论 2 348