avatar

Catalog
玩转webpack——极客时间学习笔记

配置文件名称

  • webpack 默认配置文件:webpack.config.js
  • webpack配置组成:
    • entry——打包的入口文件(指定默认的entry为:./src/index.js
    • output ——打包的输出(指定默认的output为:./dist/main.js
    • mode ——环境
    • rules ——Loader配置
    • plugin ——插件配置

hello-world

  • 创建一个文件目录

  • 生成package.json文件

    shell
    1
    npm init -y
  • 安装webpackwebpack-cli

    shell
    1
    npm install webpack webpack-cli --save-dev   //安装至dev-dependency中
  • 创建一个webpack.config.js文件

    Javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    'use strict';

    const path = require('path')

    module.exports = {
    entry: './src/index.js',
    output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js'
    },
    mode: 'production'
    }
  • 编写入口文件

  • 打包

    shell
    1
    ./node_modules/.bin/webpack
    • 更便捷的打包方式为——在package.json文件中的srcipt中设置

      Javascript
      1
      2
      3
      4
      "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "build":"webpack"
      }
    • 设置完毕后即可使用npm run build来进行打包。

基本用法

Entry

Entry用来指定webpack的打包入口

  • 单入口——entry为一个字符串

    Javascript
    1
    entry: './src/index.js'
  • 多入口——entry为一个对象

    Javascript
    1
    2
    3
    4
    entry: {
    app: './src/app.js',
    adminApp:'./src/adminApp.js'
    }

Output

output用来告诉webpack如何将编译后的文件输出到磁盘

  • 单入口

    Javascript
    1
    2
    3
    4
    output: {
    filename:'boundle.js'.
    path:__dirname + 'dist'
    }
  • 多入口

    Javascript
    1
    2
    3
    4
    output: {
    filename:'[name].js', //通过占位符来保证名字的唯一性
    path: __dirname + 'dist'
    }

Loaders

webpack开箱即用只支持JSJSON两种文件类型,通过Loaders去支持其他文件类型并把它们转化为有效的模块。

本质是一个函数,接受源文件作为参数,返回转化的结果

  • 常见的Loaders

    名称 描述
    babel-loader 转换 ES6、ES7 等 JS 新特性语法
    css-loader 支持 .css 文件的加载和解析
    less-loader 将 less 转化为 css
    ts-loader 将 ts 转换为 js
    file-loader 进行图片、字体等的打包
    raw-loader 将文件以字符串形式导入
    thread-loader 多进程打包 js 和 css
  • 用法

    Javascript
    1
    2
    3
    4
    5
    6
    7
    module: {
    rules:[
    {test:/\/txt$/, use: 'raw-loader'}
    //test 指定匹配规则
    //use指定使用的loader名称
    ]
    }

plugins

插件用域bundle文件的优化,资源管理和环境变量注入。

作用于整个构建过程

  • 常见的Plugins

    名称 描述
    CommonsChunkPlugin 将chunks相同的模块代码提取成公共js
    CleanWebpackPlugin 清理构建目录
    ExtractTextWebpackPlugin 将css从bundle文件里提取成一个独立的css文件
    CopyWebpackPlugin 将文件或者文件夹拷贝到构建的输出目录
    HtmlWebpackPlugin 创建html文件去承载输出的bundle
    UglifyjsWebpackPlugin 压缩js
    ZipWebpackPlugin 将打包出的资源生成一个zip包
  • 用法

    Javascript
    1
    2
    3
    plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'})
    ]

mode

用来指定当前的构建环境

选项 描述
production 设置process.env.NODE_ENV的值为development。开启 NamedChunksPlugins 和 NamedModulesPlugin
development 设置process.env.NODE_ENV的值为production。开启 FlagDependencyUsagePlugin , FlagIncludedChunksPlugin, ModuleConcatenationPlugin , NoEmitOnErrorsPlugin , OccurrenceOrderPlugin, SideEffectsFlagPlugin和TerserPlugin
none 不开启任何优化选项

进阶用法

解析ES6

  • 安装babel-loader@babel/core@babel/preset-env

    shell
    1
    npm i @babel/core @babel/preset-env babel-loader -D
  • 创建.babelrc文件并配置

    Javascript
    1
    2
    3
    {
    "presents": ["@babel/preset-env"] //增加es6的babel present配置
    }
  • webpack.config.js中设置

    Javascript
    1
    2
    3
    4
    5
    6
    rules: [
    {
    test:/.js$/,
    use:'babel-loader'
    }
    ]

解析React Jsx

  • 安装react-dom@babel/preset-react

    shell
    1
    npm i react-dom @babel/preset-react -D
  • .babelrc中配置

    Javascript
    1
    2
    3
    {
    "presents": ["@babel/preset-react"]
    }
  • webpack.config.js中设置

    Javascript
    1
    2
    3
    4
    5
    6
    rules: [
    {
    test:/.js$/,
    use:'babel-loader'
    }
    ]

解析css

  • 安装

    shell
    1
    npm i style-loader css-loader -D
  • webpack.config.js中配置

    Javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    rules: [
    {
    test: /.css$/,
    use: [
    'style-loader', //将样式通过<style>标签插入到head中
    'css-loader'
    // loader调用方式为链式调用,即从右到左。所以应当先写style-loader
    ]
    }
    ]

解析less、sass

  • 安装

    shell
    1
    npm i less less-loader -D
  • 配置

    Javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    rules: [
    {
    test: /.less$/,
    use: [
    'style-loader',
    'css-loader',
    'less-loader'
    ]
    }
    ]

解析图片

  • 安装

    shell
    1
    npm i file-loader -D
  • 配置

    Javascript
    1
    2
    3
    4
    {
    test: /.(png|jpg|gif|jpeg)$/,
    use: 'file-loader'
    }

解析字体

解析字体同样是使用file-loader

  • 配置

    Javascript
    1
    2
    3
    4
    {
    test: /.(woff|woff2|eot|ttf|otf)$/,
    use: 'file-loader'
    }

解析字体和图片还可以使用url-loader,相比较于file-loader它可以设置较小资源自动base64

  • 配置

    Javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    {
    test: /.(png|jpg|gif|jpeg)$/,
    use: [{
    loader: 'url-loader',
    options: {
    limit:10240
    }
    }]
    }

文件监听

文件监听是指在发现源码发生变化时,自动重新构建出新的输出文件,有两种实现方式:

缺陷——每次需要手动刷新浏览器

  • 启动webpack命令时,带上--watch 参数

    • package.json中配置

      Javascript
      1
      2
      3
      "scripts": {
      "watch": "webpack --watch"
      }
  • 在配置webpack.config.js中设置 watch:true

    原理分析:轮询判断文件的最后编辑时间是否变化,某个文件发生了变化,并不会立刻告诉监听者,而是先缓存起来,等aggregateTimeout

    Javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    module.export = {
    //默认为flase
    watch: true,
    //只有开启监听模式时,watchOptions才有意义
    watchOption: {
    //默认为空,不监听的文件夹
    ignored: /node_modules/,
    //监听到变化后会等300ms再去执行,默认300ms
    aggregateTimeout: 300,
    //判断文件是否发生变化是通过不断询问系统指定文件有没有变化实现的,默认每秒问1000次
    poll: 1000
    }
    }

热更新——webpack-dev-server

  • 不刷新浏览器
  • 不输出文件,而是放在内存中
  • 使用HotModuleReplacementPlugin插件

使用

  • package.json文件中配置

    Javascript
    1
    2
    3
    "scripts": {
    "dev": "webpack-dev-server --open" //open参数:每次构建完成后自动开启浏览器
    }
  • webpack.config.js文件中配置

    Javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    mode: 'development' //只在开发环境中使用
    module: {
    plugins: [
    new webpack.HotModuleReplacementPlugin() //需要引入webpack
    ],
    devServer: [
    contentBase: './dist', //服务基础目录
    hot: true
    ]
    }

文件指纹

  • hash:和整个项目的构建相关,只要项目文件有修改,整个项目构建的hash值就会改变
  • Chunkhash:和webpack打包的chunk有关,不同的entry会生成不同的chunkhash
  • Contenthash:根据文件内容来定义hash,文件内容不变,则contenthash不变

使用策略:

  • js的文件指纹

    Javascript
    1
    2
    3
    4
    output: {
    path: path.join(__dirname, 'dist'),
    filename: '[name]_[chunkhash:8].js'
    }
  • 字体、图片的文件指纹

    Javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {
    test: /.(png|jpg|gif|jpeg)$/,
    use: [
    {
    loader: 'file-loader',
    options: {
    name: '[name]_[hash:8].[ext]'
    }
    }
    ]
    }
  • css的文件指纹

    • 安装插件,把css提取出来成为一个独立文件,不能与style-loader一同使用。

      shell
      1
      npm i mini-css-extract-plugin -D
    • 使用插件并配置

      Javascript
      1
      2
      3
      4
      5
      plugins: [
      new MiniCssExtractPlugin({
      filename: '[name]_[contenthash:80].css'
      })
      ]
      Javascript
      1
      2
      3
      4
      5
      6
      7
      8
      {
      test: /.css$/,
      use: [
      MiniCssExtractPlugin.loader,
      'css-loader',
      'less-loader'
      ]
      }

文件压缩

  • html压缩

    • 安装

      shell
      1
      npm i html-webpack-plugin -D
    • 引用插件,一个页面对应一个HtmlWebpackPlugin

      Javascript
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      new HtmlWebpackPlugin({
      template: path.join(__dirname, 'src/index.html'), //html模板所在位置
      filename: 'index.html', // 指定打包出来的文件名称
      chunks: ['index'], // html使用哪些chunk
      inject: true,
      minify: {
      html5: true,
      collapseWhitespace: true,
      preserveLineBreaks: false,
      minifyCSS: true,
      minifyJS: true,
      removeComments: flase
      }
      })
  • css压缩

    使用optimize-css-assets-webpack-plugin插件和cssnano预处理器

    • 安装

      shell
      1
      npm i optimize-css-assets-webpack-plugin cssnano -D
    • 引用插件

      Javascript
      1
      2
      3
      4
      new OptimizeCssAssetsPlugin({
      assetNameRegExp: /\.css$/g,
      cssProcessor: require('cssnano')
      })
  • js压缩

    内置了uglifyjs-webpack-plugin插件,自动压缩js文件。

自动清理构建目录

  • 安装

    shell
    1
    npm i clean-webpack-plugin -D
  • 引入并使用插件

    Javascript
    1
    new CleanWebpackPlugin()

自动补齐css3前缀

  • 安装

    sh
    1
    npm i postcss-loader autoprefixer -D
  • 使用loader

    Javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    use: [
    'style-loader'
    'css-loader',
    {
    loader: 'postcss-loader',
    options: {
    plugins: () => [
    require('autoprefixer')({
    browsers: ['last 2 version', '>1%', 'ios 7'] //指定所需要兼容的浏览器版本
    })
    ]
    }
    }
    ]

移动端px转换为rem

  • 安装

    shell
    1
    npm i px2rem-loader -D
    shell
    1
    npm i lib-flexible -S     //用来动态计算根元素字体的大小
  • 配置loader

    Javascript
    1
    2
    3
    4
    5
    6
    7
    {
    loader: 'px2rem-loader',
    options:{
    remUnit: 75, //一个rem=75px
    remPreCesion: 8 // px转换成rem后的小数点位数
    }
    }
  • 页面引入lib-flexible,不支持内联,需手动引入

静态资源内联

  • 安装 (注意安装版本)

    shell
    1
    npm i raw-loader@0.5.1 -D
  • 使用

    html
    1
    2
    3
    4
    5
    6
    7
    <head>
    <!--内联html-->
    ${ require('raw-loader!../meta.html')}
    <title>demo</title>
    <!-- 内联js -->
    ${ require('raw-loader!babel-loader!../../node_modules/lib-flexible/flexble.js')}
    </head>

多页面应用打包

  • 安装库

    shell
    1
    npm i glob -D
  • 设置函数

    Javascript
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    const setMPA = () => {
    const entry = {}
    const htmlWebpackPlugins = []
    const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js'))
    Object.keys(entryFiles)
    .map((index) => {
    const entryFile = entryFiles[index]
    const match = entryFile.match(/src\/(.*)index.js/)
    const pageNaem = match && match[1]
    entryFile[pageName] = entryFile
    htmlWebpackPlugins.push(
    new HtmlWebpackPlugin({
    template: path.join(__dirname, `src/${pageName}/index.html`),
    filename: `${pageName}.html`,
    chunks: [pageName],
    inject: true,
    minify: {
    html5: true,
    collapseWhitespace: true,
    preserveLineBreaks: false,
    minifyCSS: true,
    minifyJS: true,
    removeComments: flase
    }
    })
    )
    })
    return {
    entry,
    htmlWebpackPlugins
    }
    }

    const { entry, htmlWebpackPlugins} = setMPA()

    module.exports = {
    plugins: [].concat(htmlWebpackPlugins)
    }

scope hoisting

原理: 将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以防止变量名冲突。

意义:可以减少函数声明代码和内存开销

提取公共资源

使用html-webpack-externals-plugin

Author: 一只酱
Link: http://yoursite.com/2020/02/04/webpack/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶