webpack学习总结(一)——生产开发环境配置

100 阅读4分钟

webpack 是什么?

webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。
在 webpack 看来, 前端的所有资源文件(js/json/css/img/less/...)都会作为模块处理。
它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。

webpack五个核心概念

1、Entry

入口(Entry)指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。

2、Output

输出(Output)指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名。

3、Loader

Loader 让 webpack 能 够 去 处 理 那 些 非 JavaScript 文 件 (webpack 自 身 只 理 解
JavaScript) 

4、Plugins

插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,
一直到重新定义环境中的变量等。

5、Mode

模式(Mode)指示 webpack 使用相应模式的配置。

development :能让代码本地调试运行的环境,比如,编译打包 js 和 json 文件,并且es6 的模块化语法转换成浏览器能识别的语法;

production:能让代码优化上线运行的环境,在开发配置功能上再添加压缩代码等功能。

webpack开发环境基本配置

开发环境

  1. 初始化package.json 
  2. 下载并安装 webpack —— npm install webpack webpack-cli -D 
  3. 创建文件

        

4、webpack.config.js中

下载依赖

样式资源 :npm i css-loader style-loader less-loader less -D 

html资源: npm install --save-dev html-webpack-plugin

图片资源:npm install --save-dev html-loader url-loader file-loader
// resolve用来拼接绝对路径的方法

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {
  entry: './src/js/index.js', // 入口文件
  output: {
    filename: 'js/built.js', // 输出文件
    path: resolve(__dirname, 'build') // 输出路径 __dirname nodejs的变量,代表当前文件的目录绝对路径
  },
  module: {
    rules: [
      // loader的配置,不同文件必须配置不同loader处理
     // use数组中loader执行顺序:从右到左,从下到上 依次执行
      {   
            /* 处理less资源,
            style-loader 创建style标签,将js中的样式资源插入进行,添加到head中生效
          'style-loader',将css文件变成commonjs模块加载js中,里面内容是样式字符串
           less-loader,将less文件编译成css文件
        */

        test: /\.less$/,
         use: ['style-loader', 'css-loader', 'less-loader']      },
      {
        // 处理css资源
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        // 处理图片资源        
        test: /\.(jpg|png|gif)$/,
        loader: 'url-loader',
        options: {
        // 图片大小小于 8kb,就会被 base64 处理 
        // 优点: 减少请求数量(减轻服务器压力) 
        // 缺点:图片体积会更大(文件请求速度更慢)         
         limit: 8 * 1024,

          // 给图片进行重命名 // [hash:10]取图片的 hash 的前 10 位 // [ext]取文件原来扩展名
          name: '[hash:10].[ext]',

          // 关闭es6模块化
          // 问题:因为 url-loader 默认使用 es6 模块化解析,而 html-loader 引入图片是 commonjs
          // 解析时会出问题:[object Module] 
          // 解决:关闭 url-loader 的 es6 模块化,使用 commonjs 解析 

          esModule: false,
          outputPath: 'imgs'
        }
      },
      {
        // 处理html中img资源
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        // 处理其他资源
        // 排除 css/js/html 资源        
        exclude: /\.(html|js|css|less|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    /* 
    plugins的配置
     功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)需要有结构的HTML文件*/
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development',
  devServer: {
    contentBase: resolve(__dirname, 'build'),
    compress: true,
    port: 3000,
    open: true
  }
};

4、运行代码

npx webpack-dev-server

生产环境基本配置

提取 css 成单独文件

原因:webpack将css打包成js,造成js文件比较大,运行过程中要先加载js再运行css,会出现闪烁现象

npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

 module.exports = {
  ......
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          // 创建style标签,将样式放入
          // 'style-loader', 
          // 这个loader取代style-loader。作用:提取js中的css成单独文件
          MiniCssExtractPlugin.loader,
          // 将css文件整合到js文件中
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new MiniCssExtractPlugin({
      // 对输出的css文件进行重命名
      filename: 'css/built.css'
    })
  ],
  ......

};

css兼容性处理

会自动给需要兼容性处理的样式加上前缀

npm install --save-dev postcss-loader postcss-preset-env
 // 定义nodejs环境变量:决定使用browserslist的哪个环境,默认情况下会走package.json中的生产环境配置,想要走开发环境的配置,需要nodejs环境变量
process.env.NODE_ENV = 'development';

module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          /*
            帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
          */
          // 使用loader的默认配置
          // 'postcss-loader',
          // 修改loader的配置
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: () => [
                // postcss的插件
                require('postcss-preset-env')()
              ]
            }
          }
        ]
      }
    ]
  },

package.json文件中

"browserslist": {
     // 开发环境 --> 设置node环境变量:process.env.NODE_ENV = development
      "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
     ],
     // 生产环境:默认是看生产环境
     "production": [
        ">0.2%", // 大于99.8%的浏览器
        "not dead", // 不要已经死的浏览器
        "not op_mini all" // 不要op_mini
   ]
 }

压缩css

npm install --save-dev optimize-css-assets-webpack-plugin
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin' )plugins: [  // 压缩css  new OptimizeCssAssetsWebpackPlugin()],

js 语法检查

npm install --save-dev eslint-loader eslint eslint-config-airbnb-base eslint-plugin-import
module: {    rules: [      {        test: /\.js$/,        exclude: /node_modules/, // 只检查自己写的源代码,第三方的库是不用检查的        loader: 'eslint-loader',
        enforce:'pre', //优先执行, 当一个文件被多个loader处理时,一定要指定loader的执行顺序,先执行eslint再执行bable        options: {          // 自动修复eslint的错误          fix: true        }      }    ]  },

package.json中

"eslintConfig": {    "extends": "airbnb-base" } 

js兼容性处理

js兼容性处理:babel-loader @babel/core
1\. 基本js兼容性处理 --> @babel/preset-env
问题:只能转换基本语法,如promise高级语法不能转换
2\. 全部js兼容性处理 --> @babel/polyfill
问题:我只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大了~
3\. 需要做兼容性处理的就做:按需加载 --> core-js

npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/polyfill core-js

 module: {    rules: [      {        test: /\.js$/,        exclude: /node_modules/,        loader: 'babel-loader',        options: {          // 预设:指示babel做怎么样的兼容性处理          presets: [            [              '@babel/preset-env',              {                // 按需加载                useBuiltIns: 'usage',                // 指定core-js版本                corejs: {                  version: 3                },                // 指定兼容性做到哪个版本浏览器                targets: {                  chrome: '60',                  firefox: '60',                  ie: '9',                  safari: '10',                  edge: '17'                }              }            ]          ]        }      }    ]  },

js压缩

生产环境默认会压缩js

mode: 'production

压缩html

 const HtmlWebpackPlugin = require('html-webpack-plugin');plugins: [    new HtmlWebpackPlugin({      template: './src/index.html',      // 压缩html代码      minify: {        // 移除空格        collapseWhitespace: true,        // 移除注释        removeComments: true      }    })  ],

webpack生产环境配置代码

const { resolve } = require('path');const MiniCssExtractPlugin = require('mini-css-extract-plugin');const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');const HtmlWebpackPlugin = require('html-webpack-plugin');// 定义nodejs环境变量:决定使用browserslist的哪个环境process.env.NODE_ENV = 'production';// 复用loaderconst commonCssLoader = [  MiniCssExtractPlugin.loader,  'css-loader',  {    // 还需要在package.json中定义browserslist    loader: 'postcss-loader',    options: {      ident: 'postcss',      plugins: () => [require('postcss-preset-env')()]    }  }];module.exports = {  entry: './src/js/index.js',  output: {    filename: 'js/built.js',    path: resolve(__dirname, 'build')  },  module: {    rules: [      {        test: /\.css$/,        use: [...commonCssLoader]      },      {        test: /\.less$/,        use: [...commonCssLoader, 'less-loader']      },      /*        正常来讲,一个文件只能被一个loader处理。        当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:          先执行eslint 在执行babel      */      {        // 在package.json中eslintConfig --> airbnb        test: /\.js$/,        exclude: /node_modules/,        // 优先执行        enforce: 'pre',        loader: 'eslint-loader',        options: {          fix: true        }      },      {        test: /\.js$/,        exclude: /node_modules/,        loader: 'babel-loader',        options: {          presets: [            [              '@babel/preset-env',              {                useBuiltIns: 'usage',                corejs: {version: 3},                targets: {                  chrome: '60',                  firefox: '50'                }              }            ]          ]        }      },      {        test: /\.(jpg|png|gif)/,        loader: 'url-loader',        options: {          limit: 8 * 1024,          name: '[hash:10].[ext]',          outputPath: 'imgs',          esModule: false        }      },      {        test: /\.html$/,        loader: 'html-loader'      },      {        exclude: /\.(js|css|less|html|jpg|png|gif)/,        loader: 'file-loader',        options: {          outputPath: 'media'        }      }    ]  },  plugins: [    new MiniCssExtractPlugin({      filename: 'css/built.css'    }),    new OptimizeCssAssetsWebpackPlugin(),    new HtmlWebpackPlugin({      template: './src/index.html',      minify: {        collapseWhitespace: true,        removeComments: true      }    })  ],  mode: 'production'};