Skip to content

webpack 基础使用

安装

javascript
npm i -D webpack webpack-cli

配置 script 脚本

javascript
"scripts":{
	"build":"webpack src/main.js"
}

执行

javascript
npm run build

生成了 dist 文件夹,含有 main.js 说明简单的打包成功 ​

修改配置

默认配置文件是 webpack.config.js

javascript
// webpack.config.js

const path = require('path')
module.exports = {
  mode: 'development', // 开发模式
  entry: path.resolve(__dirname, '../src/main.js'), // 入口文件
  output: {
    filename: 'output.js', // 打包后的文件名称
    path: path.resolve(__dirname, '../dist') // 打包后的目录
  }
}

更改打包命令

javascript
"scripts":{
	"build":"webpack --config build/webpack.config.js"
}

配置输出文件名和输出目录位置

javascript
module.exports = {
  // 省略其他配置
  output: {
    filename: '[name].[hash:8].js', // 打包后的文件名称
    path: path.resolve(__dirname, '../dist') // 打包后的目录
  }
}

每次手动引入修改引入的 js 当然是不可容忍的,于是使用插件

javascript
npm i -D html-webpack-plugin

然后配置一个 index.html 模版

javascript
// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  mode: 'development', // 开发模式
  entry: path.resolve(__dirname, '../src/main.js'), // 入口文件
  output: {
    filename: '[name].[hash:8].js', // 打包后的文件名称
    path: path.resolve(__dirname, '../dist') // 打包后的目录
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../public/index.html')
    })
  ]
}

配置多页面入口开发

javascript
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  mode: 'development', // 开发模式
  entry: {
    main: path.resolve(__dirname, '../src/main.js'),
    header: path.resolve(__dirname, '../src/header.js')
  },
  output: {
    filename: '[name].[hash:8].js', // 打包后的文件名称
    path: path.resolve(__dirname, '../dist') // 打包后的目录
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../public/index.html'),
      filename: 'index.html',
      chunks: ['main'] // 与入口文件对应的模块名
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../public/header.html'),
      filename: 'header.html',
      chunks: ['header'] // 与入口文件对应的模块名
    })
  ]
}

自动清除上次的打包产物使用 clean-webpack-plugin 插件 ​

javascript
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
  // ...省略其他配置
  plugins: [new CleanWebpackPlugin()]
}

使用 css ​

需要加入 loader

javascript
npm i -D style-loader css-loader

如果我们用 less 则安装相应的 loader

javascript
npm i -D less less-loader

修改配置文件

javascript
// webpack.config.js
module.exports = {
  // ...省略其他配置
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'] // 从右向左解析原则
      },
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader'] // 从右向左解析原则
      }
    ]
  }
}

添加 css 前缀

javascript
npm i -D postcss-loader autoprefixer

修改配置

javascript
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader'] // 从右向左解析原则
      }
    ]
  }
}

引入 autoprefixer

  • 第一种使用 postcss.config.js
javascript
module.exports = {
  plugins: [require('autoprefixer')] // 引用该插件即可了
}
  • 第二种直接在 webpack.config.js 中配置
javascript
// webpack.config.js
module.exports = {
  //...省略其他配置
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')]
            }
          },
          'less-loader'
        ] // 从右向左解析原则
      }
    ]
  }
}

拆分 css

javascript
npm i -D mini-css-extract-plugin

webpack4.0 以前通过extract-text-webapck-plugin插件 ​

修改配置文件

javascript
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
  //...省略其他配置
  module: {
    rules: [
      {
        test: /\.less$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[hash].css',
      chunkFilename: '[id].css'
    })
  ]
}

拆分多个 css 上面用到的 mini-css-extract-plugin 会将所有的 css 样式合并为一个 css 样式,而拆分为一个个对应的多个 css 文件需要用到 extract-text-webpack-plugin,而目前 mini-css-extract-plugin 还不支持此功能,安装 extract-text-webpack-plugin ​

javascript
npm i extract-text-webpack-plugin@next
javascript
// webpack.config.js

const path = require('path')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
let indexLess = new ExtractTextWebpackPlugin('index.less')
let indexCss = new ExtractTextWebpackPlugin('index.css')
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: indexCss.extract({
          use: ['css-loader']
        })
      },
      {
        test: /\.less$/,
        use: indexLess.extract({
          use: ['css-loader', 'less-loader']
        })
      }
    ]
  },
  plugins: [indexLess, indexCss]
}

处理文件、图片等 file-loader: 处理文件名解析 url,并将文件移动到输出的目录中 url-loader:一般与 file-loader 搭配使用,功能和 file-loader 类似,但是如果文件小于限制会编码 base64,否则使用 file-loader 移动文件到输出目录 ​

javascript
// webpack.config.js
module.exports = {
  // 省略其它配置 ...
  module: {
    rules: [
      // ...
      {
        test: /\.(jpe?g|png|gif)$/i, //图片文件
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10240,
              fallback: {
                loader: 'file-loader',
                options: {
                  name: 'img/[name].[hash:8].[ext]'
                }
              }
            }
          }
        ]
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, //媒体文件
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10240,
              fallback: {
                loader: 'file-loader',
                options: {
                  name: 'media/[name].[hash:8].[ext]'
                }
              }
            }
          }
        ]
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i, // 字体
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10240,
              fallback: {
                loader: 'file-loader',
                options: {
                  name: 'fonts/[name].[hash:8].[ext]'
                }
              }
            }
          }
        ]
      }
    ]
  }
}

babel 转义 js 文件 ​

javascript
npm i -D babel-laoder @babel/preset-env @babel/core

注意 babel-loader 与 babel-core 版本对应 ​

  • babel-loader 8.x 对应 babel-core 7.x
  • babel-laoder 7.x 对应 babel-core 6.x

javascript
// webpack.config.js
module.exports = {
  // 省略其它配置 ...
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        },
        exclude: /node_modules/
      }
    ]
  }
}

上面的 babel-loader 只会将 ES6/7/8 语法转换为 ES5 语法,但是对新 api 并不会转换 例如(promise、Generator、Set、Maps、Proxy 等) 此时我们需要借助 babel-polyfill 来帮助我们转换

javascript
npm i @babel/polyfill
javascript
// webpack.config.js
const path = require('path')
module.exports = {
  entry: ['@babel/polyfill', path.resolve(__dirname, '../src/index.js')] // 入口文件
}

配置 webpack-dev-server 进行热更新

javascript
npm i -D webpack-dev-server
javascript
const Webpack = require('webpack')
module.exports = {
  // ...省略其他配置
  devServer: {
    port: 3000,
    hot: true,
    contentBase: '../dist'
  },
  plugins: [new Webpack.HotModuleReplacementPlugin()]
}

一份完整的 vue 配置

javascript
// webpack.config.js
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
const vueLoaderPlugin = require('vue-loader/lib/plugin')
const Webpack = require('webpack')
module.exports = {
  mode: 'development', // 开发模式
  entry: {
    main: path.resolve(__dirname, '../src/main.js')
  },
  output: {
    filename: '[name].[hash:8].js', // 打包后的文件名称
    path: path.resolve(__dirname, '../dist') // 打包后的目录
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: ['vue-loader']
      },
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [['@babel/preset-env']]
          }
        }
      },
      {
        test: /\.css$/,
        use: [
          'vue-style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')]
            }
          }
        ]
      },
      {
        test: /\.less$/,
        use: [
          'vue-style-loader',
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')]
            }
          },
          'less-loader'
        ]
      }
    ]
  },
  resolve: {
    alias: {
      vue$: 'vue/dist/vue.runtime.esm.js',
      ' @': path.resolve(__dirname, '../src')
    },
    extensions: ['*', '.js', '.json', '.vue']
  },
  devServer: {
    port: 3000,
    hot: true,
    contentBase: '../dist'
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../public/index.html'),
      filename: 'index.html'
    }),
    new vueLoaderPlugin(),
    new Webpack.HotModuleReplacementPlugin()
  ]
}

区分开发环境

  • webpack.dev.js
  • webpack.prod.js
javascript
生产环境主要实现的是压缩代码、提取css文件、合理的sourceMap、分割代码
需要安装以下模块:
npm i -D  webpack-merge copy-webpack-plugin optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin
  • webpack-merge 合并配置
  • copy-webpack-plugin 拷贝静态资源
  • optimize-css-assets-webpack-plugin 压缩 css
  • uglifyjs-webapck-plugin 压缩 js

    webpack mode 设置 production 的时候会自动压缩 js 代码。原则上不需要引入 uglifyjs-webpack-plugin 进行重复工作。但是 optimize-css-assets-webpack-plugin 压缩 css 的同时会破坏原有的 js 压缩,所以这里我们引入 uglifyjs 进行压缩

javascript
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const vueLoaderPlugin = require('vue-loader/lib/plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const devMode = process.argv.indexOf('--mode=production') === -1
module.exports = {
  entry: {
    main: path.resolve(__dirname, '../src/main.js')
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: 'js/[name].[hash:8].js',
    chunkFilename: 'js/[name].[hash:8].js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        },
        exclude: /node_modules/
      },
      {
        test: /\.vue$/,
        use: [
          {
            loader: 'vue-loader',
            options: {
              compilerOptions: {
                preserveWhitespace: false
              }
            }
          }
        ]
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../dist/css/',
              hmr: devMode
            }
          },
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')]
            }
          }
        ]
      },
      {
        test: /\.less$/,
        use: [
          {
            loader: devMode ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
            options: {
              publicPath: '../dist/css/',
              hmr: devMode
            }
          },
          'css-loader',
          'less-loader',
          {
            loader: 'postcss-loader',
            options: {
              plugins: [require('autoprefixer')]
            }
          }
        ]
      },
      {
        test: /\.(jep?g|png|gif)$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 10240,
            fallback: {
              loader: 'file-loader',
              options: {
                name: 'img/[name].[hash:8].[ext]'
              }
            }
          }
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 10240,
            fallback: {
              loader: 'file-loader',
              options: {
                name: 'media/[name].[hash:8].[ext]'
              }
            }
          }
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
        use: {
          loader: 'url-loader',
          options: {
            limit: 10240,
            fallback: {
              loader: 'file-loader',
              options: {
                name: 'media/[name].[hash:8].[ext]'
              }
            }
          }
        }
      }
    ]
  },
  resolve: {
    alias: {
      vue$: 'vue/dist/vue.runtime.esm.js',
      ' @': path.resolve(__dirname, '../src')
    },
    extensions: ['*', '.js', '.json', '.vue']
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../public/index.html')
    }),
    new vueLoaderPlugin(),
    new MiniCssExtractPlugin({
      filename: devMode ? '[name].css' : '[name].[hash].css',
      chunkFilename: devMode ? '[id].css' : '[id].[hash].css'
    })
  ]
}

webpack.dev.js

javascript
const Webpack = require('webpack')
const webpackConfig = require('./webpack.config.js')
const WebpackMerge = require('webpack-merge')
module.exports = WebpackMerge(webpackConfig, {
  mode: 'development',
  devtool: 'cheap-module-eval-source-map',
  devServer: {
    port: 3000,
    hot: true,
    contentBase: '../dist'
  },
  plugins: [new Webpack.HotModuleReplacementPlugin()]
})

webpack.prod.js

javascript
const path = require('path')
const webpackConfig = require('./webpack.config.js')
const WebpackMerge = require('webpack-merge')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = WebpackMerge(webpackConfig, {
  mode: 'production',
  devtool: 'cheap-module-source-map',
  plugins: [
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '../public'),
        to: path.resolve(__dirname, '../dist')
      }
    ])
  ],
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        //压缩js
        cache: true,
        parallel: true,
        sourceMap: true
      }),
      new OptimizeCssAssetsPlugin({})
    ],
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        libs: {
          name: 'chunk-libs',
          test: /[\\/]node_modules[\\/]/,
          priority: 10,
          chunks: 'initial' // 只打包初始时依赖的第三方
        }
      }
    }
  }
})

如有转载或 CV 的请标注本站原文地址