从零配置简单Webpack

一、安装

npm init -y
npm install webpack webpack-cli --save-dev

注意:npm初始化后的 package.json 里的 name 属性不能与 webpack 同名。

二、创建配置文件

一般有两种方法:

  1. 基础配置文件 + 开发环境配置文件 + 生产环境配置文件
  2. 开发环境配置文件 + 生产环境配置文件

这里用第二种:根目录下创建 webpack.dev.js 和 webpack.prod.js 两个文件。

然后在 package.json 里添加两个脚本:

"build": "webpack --config webpack.prod.js",
"dev": "webpack-dev-server --config webpack.dev.js"

三、安装常用loader和plugin

安装:

npm install webpack-dev-server --save-dev
npm install html-webpack-plugin --save-dev
npm install css-loader --save-dev
npm install style-loader --save-dev
npm install sass-loader node-sass --save-dev
npm install clean-webpack-plugin --save-dev
npm install @babel/core @babel/preset-env babel-loader --save-dev
npm install file-loader --save-dev
npm install url-loader --save-dev
npm install html-loader --save-dev
npm install mini-css-extract-plugin --save-dev
npm install postcss-preset-env postcss-loader --save-dev
npm install optimize-css-assets-webpack-plugin --save-dev
npm install @babel/polyfill --save-dev
npm install core-js --save-dev

作用:

  • webpack-dev-server:开启调试的服务器。
  • html-webpack-plugin:处理html。
  • css-loader:处理css文件。
  • style-loader:将处理好的css代码引入到style标签内。
  • sass-loader node-sass:处理sass。
  • clean-webpack-plugin:在重新生成打包文件夹前将dist文件夹删除。
  • @babel/core @babel/preset-env babel-loader:大部分 es6–>es5,promise 等无法转换。
  • file-loader:处理各类资源文件(字体图标、视频等)。
  • url-loader:处理(图片)路径。
  • html-loader:处理html内的img标签。
  • mini-css-extract-plugin:将css代码从bundle.js中分离成单个文件。
  • postcss-preset-env postcss-loader:前者处理css最新语法的兼容性问题,自动加浏览器内核前缀,注意在package.json配置browserslist;后者是处理css的工具集,看具体配置了什么。
  • optimize-css-assets-webpack-plugin:压缩css。
  • @babel/polyfill:谨慎引入polyfill,会导致打包后的js文件变巨大,用法是在入口文件引入import ‘@babel/polyfill’,配置文件无需更改。
  • core-js:按需处理js兼容性问题,就不再需要 @babel/polyfill 了。

四、附录

// package.json
"browserslist":{
    "development":[
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ],
    "production":[
      ">0.2%",
      "not dead",
      "not op_mini all"
    ]
}
// 测试browserlist里的开发环境,需要给Node.js定环境变量,
// 而不是修改webpack的开发模式(默认为生产环境)。
// webpack.dev.js
process.env.NODE_ENV = 'development'
// webpack.dev.js
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
module.exports = {
  mode: 'development',
  entry: resolve(__dirname, 'src', 'index.js'),
  output: {
    filename: 'bundle.js',
    path: resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader, 
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss', // webpack要求要给的唯一标识
              plugins:()=>[
                require('postcss-preset-env')()
              ]
            }
          }
        ]
      },
      {
        test: /\.scss$/,
        use: [{
          loader: MiniCssExtractPlugin.loader // 将 JS 字符串生成为 style 节点
        }, {
          loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
        }, {
          loader: "sass-loader" // 将 Sass 编译成 CSS
        }]
      },
      {
        test: /\.js$/,
        loader: ['babel-loader'],
        include: resolve(__dirname, 'src'),
        exclude: /node_modules/,
        options:{
          presets:[
            '@babel/preset-env',
            {
              // 按需加载
              useBuiltIns: 'usage',
              // 指定core-js版本
              corejs:{
                version: 3
              },
              // 指定兼容性做到哪个版本浏览器
              target:{
                chrome: '60',
                firefox: '60',
                ie: '9',
                safari: '10',
                edge: '17'
              }
            }
          ]
        }
      },
      {
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              name: '[hash:5].[ext]',
              limit: 8192,
              // 默认情况下url-loader用es6的方法引入,跟html-loader配合时会出错,所以要设置为false
              esModule: false
            }
          }
        ]
      },
      {
        test: /\.(html)$/,
        use: {
          loader: 'html-loader'
        }
      },
      {
        test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/,
        // 或者排除html/css/js/scss等其他处理过的
        // exclude: /\.(html|css|js|scss)$/,
        loader: ' file-loader',
        options: {
          name: '[hash:5].[ext]'
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      // 模板
      template: resolve(__dirname, 'src', 'index.html'),
      // 输出文件名
      filename: 'index.html'
    }),
    // 使用MiniCssExtractPlugin就要把所有style-loader换成MiniCssExtractPlugin.loader
    new MiniCssExtractPlugin({
      // filename: 'css/main.css'
    }),
    new OptimizeCssAssetsPlugin()
  ],
  devServer: {
    port: 3000,
    contentBase: resolve(__dirname, 'dist'),
    open: true,
    compress: true,
    hot: true
  },
  // 方便调试
  devtool: 'cheap-module-eval-source-map'
}
const { resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')

module.exports = {
  mode: 'production',
  entry: resolve(__dirname, 'src', 'index.js'),
  output: {
    filename: 'bundle.js',
    path: resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss', // webpack要求要给的唯一标识
              plugins:()=>[
                require('postcss-preset-env')()
              ]
            }
          }
        ]
      },
      {
        test: /\.scss$/,
        use: [{
          loader: MiniCssExtractPlugin.loader // 将 JS 字符串生成为 style 节点
        }, {
          loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
        }, {
          loader: "sass-loader" // 将 Sass 编译成 CSS
        }]
      },
      {
        test: /\.js$/,
        loader: ['babel-loader'],
        include: resolve(__dirname, 'src'),
        exclude: /node_modules/,
        options:{
          presets:[
            '@babel/preset-env',
            {
              // 按需加载
              useBuiltIns: 'usage',
              // 指定core-js版本
              corejs:{
                version: 3
              },
              // 指定兼容性做到哪个版本浏览器
              target:{
                chrome: '60',
                firefox: '60',
                ie: '9',
                safari: '10',
                edge: '17'
              }
            }
          ]
        }
      },
      {
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              name: '[hash:5].[ext]',
              limit: 8192,
              // 默认情况下url-loader用es6的方法引入,跟html-loader配合时会出错,所以要设置为false
              esModule: false
            }
          }
        ]
      },
      {
        test: /\.(html)$/,
        use: {
          loader: 'html-loader'
        }
      },
      {
        test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/,
        // 或者排除html/css/js/scss等其他处理过的
        // exclude: /\.(html|css|js|scss)$/,
        loader: ' file-loader',
        options: {
          name: '[hash:5].[ext]'
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      // 模板
      template: resolve(__dirname, 'src', 'index.html'),
      // 输出文件名
      filename: 'index.html',
      // 压缩HTML
      minify:{
        collapseWhitespace: true,
        removeComments: true
      }
    }),
    // 使用MiniCssExtractPlugin就要把所有style-loader换成MiniCssExtractPlugin.loader
    new MiniCssExtractPlugin({
      // filename: 'css/main.css'
    }),
    new OptimizeCssAssetsPlugin()
  ],
  // 分割代码,像vue的脚手架生成的js文件一样有多个,也即多个chunk。并且会分析有无相同的文件。
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  }
}

开发环境和生产环境的配置,按实际情况更改。

例如配置eslint,上面无配置,一般ide就能实现,这里仅作补充。

npm install eslint-config-airbnb-base eslint-plugin-import eslint --save-dev
// webpack配置文件
{
  test: /\.js$/,
  exclude: /node_modules/,
  loader: 'eslint-loader',
  options: {
    fix: true
  }
}
// package.json
"eslintConfig": {
    "extends": "airbnb-base"
}

五、参考

https://www.webpackjs.com/

https://juejin.im/post/5b4609f5e51d4519596b66a7

https://www.npmjs.com/package/postcss-loader

https://www.babeljs.cn/

https://www.npmjs.com/package/postcss-preset-env


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

资源加载标签和页面加载 Previous
浏览器渲染机制 Next