webpack从入门到精通学习笔记(2020-9-26整理第一章)

256 阅读14分钟

前言:本文是基于网络教程视频自学而总结的webpack从入门到精通学习笔记。💖💖

需要教程视频资源的可以私信我 免费免费免费免费免费免费免费免费免费免费 领取💖💖

还可以上网冲浪搜索关键字webpack找到同款网络教程视频💖💖

一起进步 一起掘金 Fighting💖💖

1.webpack的概念

  • 将浏览器不能识别的文件或者语法通过webpack魔法般巧妙的让浏览器能够读懂并识别显示出来

  • 构建工具中的一种webpack(静态模块打包器 module bundle)应运而生

  • 基本原理:确定一个入口文件,webpack去分析该入口文件的所有依赖,确定好所需的依赖后将他们捆绑为代码块(chuck),在通过chuck将他们分别解析成浏览器能够识别并读懂的文件显示出来(例如.less转为.css,.js转为.js等等)并输出出去(输出文件为bundle)

2.webpack的五个核心概念和最基本模板

  • Entry(入口)

  • Ouput(输出)

  • Loader----webpack只能理解javascript,其他活需要一个能帮得上忙的中级装卸工(Loader)----使用方式:先下载再使用

  • Plugins----高级装卸工(能做更多事情) ----先下载再引入再使用

  • Mode----development(开发模式---本地能运行即可)|production(生产模式---上线运行得考虑优化、性能等问题)

        webpack.config.js---最基本模板
    
    
        module.exports = {
        // webpack配置  
        // 入口起点  entry: '',  
        // 输出  output: {    
    
        // 输出文件名    
        filename: 'xxx',
    
    // 输出路径    
    // __dirname nodejs的变量,代表当前文件(webpack.config.js)的目录绝对路径    
    path: resolve(__dirname, 'xxx')  
    
    },  
    
    // loader的配置  
    module: {
        rules: [      
            // 详细loader配置      
            // 不同文件必须配置不同loader处理
            // 一个loader配置写在一个对象{}里          
                ]  
              },  
        // plugins的配置  
       plugins: [
        // 详细plugins的配置  
                ],  
    
        // 模式  
        mode: 'development', // 开发模式 
       // mode: 'production' //生产模式
         }
    

3.webpack初体验

  • cnpm init 初始化package.json

  • cnpm i webpack webpack-cli -g 全局安装webpack和webpack-cli

  • 全局安装遇到之前有安装过的包会发生新的安装包覆盖旧的安装包

  • cnpm i webpack webpack-cli --save-dev 安装全局依赖后再在本地开发环境中安装两个依赖包

  1. 遇到的第一个问题:终端显示:webpack : 无法加载文件 C:\Program Files\nodejs\webpack.ps1,因为在此系统上禁止运行脚本。

   1.第一个问题的解决方案:

  • 先以管理员的身份运行vscode

  • 在打开终端执行输入: get-ExecutionPolicy 显示Restricted,表示状态是禁止的

  • 然后在执行:set-ExecutionPolicy RemoteSigned  

  • 这时再执行get-ExecutionPolicy就显示RemoteSigned,此时在进行打包就没有问题了

  • node .\build\built.js 通过node环境运行js代码

  • 修改目录代码后得重新运行打包代码指令(webpack)才会更新最新代码输出到指定位置

    3.webpack初体验心得总结

    运行指令: 开发环境:webpack ./src/index.js -o ./build/built.js --mode=development webpack会以 ./src/index.js 为入口文件开始打包,打包后输出到 ./build/built.js

    生产环境:webpack ./src/index.js -o ./build/built.js --mode=production webpack会以 ./src/index.js 为入口文件开始打包,打包后输出到 ./build/built.js

    webpack能处理js/json资源,不能处理css/img等其他资源 生产环境和开发环境将ES6模块化编译成浏览器能识别的模块化 生产环境比开发环境多一个压缩js代码。 生产环境会压缩输出的js代码(mode:production)

4.webpack新体验之开发环境的配置

4.1打包样式资源

  • 当遇到无法直接通过webpack打包的文件时,例如.less文件,这时候需要请出中级装卸工Loader出马来家里帮忙,你的家里在哪里呢?这时候需要新建一个文件名为webpack.config.js

  • webpack.config.js是webpack的配置文件,他的作用:是指示 webpack 干哪些活(当你运行 webpack 指令时,会加载里面的配置。

  • **所有构建工具都是基于nodejs平台运行的~模块化默认采用commonjs。
    **

4.1以此时的目录结构分析代码

  • 可以统一再最外层下载所有依赖,因为webpack运行时先去寻找当前目录中的package.json中是否有安装依赖包,但是也可以去寻找外层目录文件package.json(先cnpm init)中是否有相关依赖包,所以可以统一再最外层目录(cnpm init)将所有依赖包托管在这里

4.1打包样式资源------解决了.css文件和.less文件无法打包的问题


webpack.config.js的基本配置
运行指令webpack


// resolve用来拼接绝对路径的方法
const { resolve } = require('path');

module.exports = {
  // webpack配置
  
  // 入口起点--分析内部依赖
  entry: './src/index.js',
  
  
  // 输出
  output: {
    // 输出文件名
    filename: 'built.js',
    // 输出总目录(自动创建)
    // __dirname nodejs的变量,代表当前文件(webpack.config.js)的目录绝对路径
    path: resolve(__dirname, 'build')
  },
  // loader的配置
  module: {
    rules: [
      // 详细loader配置
      // 不同文件必须配置不同loader处理
      {
        // 匹配哪些文件
        test: /\.css$/,
        // 使用哪些loader进行处理
        use: [
          // use数组中loader执行顺序:从右到左,从下到上 依次执行
          // 以这里来说先执行 'css-loader' 再执行 'style-loader'
          
          // 依赖包安装步骤
          // cnpm i webpack webpack-cli -D
          // cnpm i css-loader style-loader -D(--save-dev) 
          
          // 作用:创建style标签,将js中的样式资源插入进行,添加到head中生效
          'style-loader',
          
          // 作用:将css文件变成commonjs模块加载js中,里面内容是样式字符串
          'css-loader'
        ]
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          

          // 将less文件编译成css文件
          // 需要下载 less-loader和less
          //cnpm i less-loder less -D
          
          'less-loader'
        ]
      }
    ]
  },
  // plugins的配置
  plugins: [
    // 详细plugins的配置
  ],
  // 模式
  mode: 'development', // 开发模式
  // mode: 'production'
}

4.2打包HTML资源

4.2 以此时的目录结构分析代码

4.2打包HTML资源------解决了HTML需要自己引入结构js代码和样式CSS代码问题


webpack.config.js的基本配置
运行指令webpack

/*
  loader: 1. 下载   2. 使用(配置loader)
  plugins: 1. 下载  2. 引入  3. 使用
*/
const { resolve } = require('path');

//插件的使用方法---三步曲
//第一步:下载 cnpm i html-webpack-plugin -D
//第二步:引入
const HtmlWebpackPlugin = require('html-webpack-plugin');


module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      // loader的配置
    ]
  },
  plugins: [
    // plugins的配置
    
    
    // 第三步:使用html-webpack-plugin
    // 功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
    // 需求:需要有结构的HTML文件
    new HtmlWebpackPlugin({
      // 复制 './src/index.html' 文件,并 自动引入 打包输出的所有资源(JS/CSS)
      //因为是自动引入 所以不要再自己再去引入  .js/...等资源(画蛇添足)
      template: './src/index.html'
    })
  ],
  mode: 'development'
};

4.3打包图片资源

  • 问题:打包图片资源出错

4.3 以此时的目录结构分析代码

4.3 打包图片资源----解决了打包图片资源出错的问题

此时的页面 index.html  的代码
注意事项一:没有引入index.less(webpack自动帮忙引入)


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>webpack</title>
</head>
<body>
  <div id="box1"></div>
  <div id="box2"></div>
  <div id="box3"></div>
  
  //如果单单使用“url-loader”默认是处理不了html中的img图片的
  //可以在多用一个"html-loader"(负责html页面中引入的img标签,从而能被url-loader进行处理)
  <img src="./angular.jpg" alt="angular">
</body>
</html>

4.3 打包图片资源----解决了打包图片资源出错的问题

此时的页面 webpack.config.js 的代码


//拼接路径
const { resolve } = require('path');

//引入'html-webpack-plugin'
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  
  
  output: {
  	//输出文件名
    filename: 'built.js',
    //输出目录路径(绝对路径)
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.less$/,
        // 要使用多个loader处理用use(从右往左)
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        
        // 处理图片资源
        test: /\.(jpg|png|gif)$/,
        
        // 使用一个loader
        // 下载 url-loader file-loader
        //  url-loader 依赖于  file-loader
        // cnpm i url-loader file-loader -D
		
        // 问题:默认处理不了html中img图片
        loader: 'url-loader',
        options: {
        
          // 图片大小小于8kb,就会被base64处理
          //图片大小在8kb-12kb时使用base64处理是可以的具体看项目中使用的图片大小而定限制条件
          // 优点: 减少请求数量(减轻服务器压力)
          // 缺点:图片体积会更大(文件请求速度更慢)
          limit: 8 * 1024,
          
          
          // 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
          // 解析时会出问题:<img src="[object Module]" alt=""/>
          // 解决:关闭url-loader的es6模块化,使用commonjs解析
          esModule: false,
          
          
          // 给图片进行重命名
          // [hash:10]取图片的hash的前10位
          // [ext]取文件原来扩展名
          name: '[hash:10].[ext]'
        }
      },
      {
        test: /\.html$/,
        //cnpm i html-loader -D
        // 处理html文件的img图片(负责引入img,从而能被url-loader进行处理)
        loader: 'html-loader'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
    //复制 './src/index.html' 文件,并 自动引入 打包输出的所有资源(JS/CSS)
      template: './src/index.html'
    })
  ],
  mode: 'development'
};

4.4 打包其他资源----例如字体资源

  • **以引入字体图标iconfont为例---4.4 以此时的目录结构分析代码
    **

4.4打包其他资源------解决了其他资源打包的问题
此时的页面 index.html  的代码
注意事项一:没有引入index.less(webpack自动帮忙引入)
注意事项二:index.html   ---在此页面中并没有引入<link rel="stylesheet" href="./iconfont.css">
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>webpack</title>
</head>
<body>
  <span class="iconfont icon-icon-test"></span>
  <span class="iconfont icon-icon-test2"></span>
  <span class="iconfont icon-icon-test3"></span>
  <span class="iconfont icon-icon-test1"></span>
</body>
</html>

此时的页面  index.js  的代码 ---入口文件  

// 引入 iconfont 样式文件
import './iconfont.css';

此时的页面 webpack.config.js 的代码 


const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },


      // 打包其他资源(除了html/js/css资源以外的资源)
      {
        // 排除css/js/html资源 
        // 将处理过的资源排除掉---将来的场景可能需要排除更多
        exclude: /\.(css|js|html|less)$/,
        
        //cnpm i file-loader -D
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]'
        }
      }


    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development'
};
  • 4.4 打包后的目录结构

4.5 devserver的使用

  • 4.5结构目录--基于 4.4打包其他资源----例如字体资源 的目录文件

此时的页面 webpack.config.js 的代码 

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },


      // 打包其他资源(除了html/js/css资源以外的资源)
      {
        // 排除css/js/html资源
        exclude: /\.(css|js|html|less)$/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]'
        }
      }


    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development',
  
  
	
  // 可以单独设置开发服务器 devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器~~)
  // 特点:只会在内存中编译打包,不会有任何输出
  
  
  
  // 预先工作:cnpm i install webpack-dev-server -D
  // 启动devServer指令为:npx webpack-dev-server
  devServer: {
    // 项目构建后路径
    // 要和 ouput中的path: resolve(__dirname, 'build')保持一致
    contentBase: resolve(__dirname, 'build'),
    // 启动gzip压缩
    compress: true,
    // 端口号
    port: 3000,
    // 自动打开浏览器
    open: true
  }
};

4.1-5 webpack新体验之开发环境的配置汇总

当目录结构构建好之后,一定要注意各个文件中引入的路径是否正确

此时的页面  ./src/index.html 的代码

//路径要跟着变化

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>开发环境配置</title>
</head>

<body>
  <h1>开发环境配置</h1>
  <span class="iconfont icon-icon-test"></span>
  <span class="iconfont icon-icon-test2"></span>
  <span class="iconfont icon-icon-test3"></span>
  <span class="iconfont icon-icon-test1"></span>
  <div id="box"></div>
  
  //路径要跟着变化
  <img src="./imgs/vue.jpg" alt="vue">
  <img src="./imgs/react.png" alt="react">
</body>

</html>

此时的页面 ./src/css/iconfont.css 的代码

//路径要跟着变化

@font-face {font-family: "iconfont";
  src: url('../media/iconfont.eot?t=1581833245354'); /* IE9 */
  src: url('../media/iconfont.eot?t=1581833245354#iefix') format('embedded-opentype'), /* IE6-IE8 */
  url('../media/iconfont.woff?t=1581833245354') format('woff'),
  url('../media/iconfont.ttf?t=1581833245354') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
  url('../media/iconfont.svg?t=1581833245354#iconfont') format('svg'); /* iOS 4.1- */
}

此时的页面 ./src/css/index.less 的代码
 
//路径要跟着变化

#box {
  width: 200px;
  height: 200px;
  background-image: url('../imgs/angular.jpg');
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

此时的页面 ./js/index.js  的代码

//路径要跟着变化

import '../css/iconfont.css';
import '../css/index.less';

此时的页面 webpack.config.js   的代码



/*
  开发环境配置:能让代码运行即可
  运行项目指令:
  webpack 会将打包结果输出出去(产生输出目录等...)
  npx webpack-dev-server 只会在内存中编译打包,没有输出(WDS不会产生输出目录等...)
*/


/*
样式文件(.css|.less|.scss)和js是在一起的,不会单独输出为文件---后续要针对此项进行优化
*/


/*
  loader: 1. 下载   2. 使用(配置loader)
  plugins: 1. 下载  2. 引入  3. 使用
*/



/*
  开发环境配置:能让代码运行
    运行项目指令:
      webpack 会将打包结果输出出去
      npx webpack-dev-server 只会在内存中编译打包,没有输出
*/



// resolve用来拼接绝对路径的方法
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // 入口起点--分析内部依赖
  entry: './src/js/index.js',
  // 输出
  output: {
    // 输出文件名
    //输出到js目录下的built.js
    filename: 'js/built.js',
    // 输出总目录
    // __dirname nodejs的变量,代表当前文件(webpack.config.js)的目录绝对路径
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      // loader的配置
      // 详细loader配置
      // 不同文件必须配置不同loader处理
      {
        // 处理less资源
        //use数组中loader执行顺序:从右到左,从下到上 依次执行
        //'style-loader'作用:创建style标签,将js中的样式资源插入进行,添加到head中生效
        // 'css-loader'作用:将css文件变成commonjs模块加载js中,里面内容是样式字符串
        //'less-loader'将less文件编译成css文件,需要下载 less-loader和less
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        // 处理css资源
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        // 处理图片资源
        test: /\.(jpg|png|gif)$/,

        // 下载 url-loader file-loader才能使用'url-loader'处理img图片
        //'url-loader' 是在 'file-loader'的功能基础上做的优化
        // 如果单单使用“url-loader”默认是处理不了html中的img图片的
        // 可以在多用一个"html-loader"(负责引入img,从而能被url-loader进行处理)
        loader: 'url-loader',
        options: {
          
          // 图片大小小于8kb,就会被base64处理
          limit: 8 * 1024,

          // 给图片进行重命名
          // [hash:10]取图片的hash的前10位
          // [ext]取文件原来扩展名
          name: '[hash:10].[ext]',
          // 关闭es6模块化开启commonJs
          esModule: false,

          //输出到imgs目录下
          outputPath: 'imgs'
        }
      },
      {
        // 处理htmlimg资源
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        // 处理其他资源
        exclude: /\.(html|js|css|less|jpg|png|gif)/,
        
        //原封不动的输出资源
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          //输出到media目录下
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    // plugins的配置

    // 'html-webpack-plugin'的功能:默认会创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS)
    // 'html-webpack-plugin'的需求:需要有结构的HTML文件
    new HtmlWebpackPlugin({
      //以谁为模板
      //// 复制 './src/index.html' 文件,并 自动引入 打包输出的所有资源(JS/CSS)
      template: './src/index.html'
    })
  ],
  mode: 'development',


  	
  // 可以单独设置开发服务器 devServer:用来自动化(自动编译,自动打开浏览器,自动刷新浏览器~~)
  // 特点:只会在内存中编译打包,不会有任何输出
  devServer: {
    // 项目构建后路径与 Output下的path: resolve(__dirname, 'build')保持一致
    contentBase: resolve(__dirname, 'build'),
     // 启动gzip压缩
    compress: true,
    port: 3000,
     // 自动打开浏览器
    open: true
  }
};
  • 4.1-5 执行后的目录结构为

5.webpack新体验之生产环境的配置

1.对比开发环境中css是被打包进js文件中的,会使得js文件体积臃肿
并且因为他是先加载js文件再去加载css文件,会出现闪屏现象
2.代码压缩处理
3.兼容性问题

不应该放在开发环境下来做这些事情,会导致开发速度减慢
但是这一切都是为了代码能够在各大浏览器平稳快速的运行

5.1 生产环境下该做的第一件事:提取css成单独文件 

5.1此时的目录结构为

此时的页面 webpack.config.js 的代码


const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

//cnpm i mini-css-extract-plugin(插件先下载再引入再使用)
//提取js中的css成单独文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

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

5.1执行webpack后的目录结构为

5.1执行webpack后index.html的页面引入样式(css)的方式为

此时的页面 build/index.html 的代码
 


<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>webpack</title>
  
//用link标签引入了相关的css文件而不是style标签引入不会再出现闪屏现象
//同时减少了js/built.js的代码体积
<link href="css/built.css" rel="stylesheet">

</head>
<body>
  <div id="box1"></div>
  <div id="box2"></div>
<script type="text/javascript" src="js/built.js"></script></body>
</html>

5. 2 生产环境下该做的第二件事:css兼容性处理

此时的页面 webpack.config.js  的代码


const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

// 设置nodejs环境变量  才会去根据开发环境的配置来生效
//可以理解为进程中环境的node环境看的是开发环境还是生产环境(默认)
// process.env.NODE_ENV = 'development';

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          //使用 'css-loader'的默认配置
          'css-loader',
          /*
            css兼容性处理:postcss --> postcss-loader postcss-preset-env
            //cnpm i postcss-loader postcss-preset-env -D
            //loader:postcss-loader  plugins:postcss-preset-env


            帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
            
            
            
            写在总依赖的package.json文件中
            "browserslist": {
              // 开发环境 --> 除非设置node环境变量:process.env.NODE_ENV = development 才会去根据开发环境的配置来生效
              "development": [
                "last 1 chrome version",
                "last 1 firefox version",
                "last 1 safari version"
              ],
              // 生产环境:默认是看生产环境,与mode: 'development'无关
              "production": [
                ">0.2%",
                "not dead",
                "not op_mini all"
              ]
            }
          */

          /**
           *    使用'postcss-loader'的默认配置
                {
                loader:'postcss-loader'
                },
           */
       
          
          
          // 对象的写法来修改loader的配置
          //帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: () => [
                // 使用postcss的插件
                require('postcss-preset-env')()
              ]
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new MiniCssExtractPlugin({
      filename: 'css/built.css'
    })
  ],
  mode: 'development'
};

5. 3 生产环境下该做的第三件事:压缩css代码

此时的页面 webpack.config.js  的代码   //运行webpack看效果

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');



//引入压缩css的插件'optimize-css-assets-webpack-plugin'
//cnpm i optimize-css-assets-webpack-plugin -D
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')



// 设置nodejs环境变量
// process.env.NODE_ENV = 'development';

module.exports = {
  entry: './src/js/index.js',
  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: () => [
                // postcss的插件
                require('postcss-preset-env')()
              ]
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new MiniCssExtractPlugin({
      filename: 'css/built.css'
    }),
    // 压缩css  插件都是new调用
    new OptimizeCssAssetsWebpackPlugin()
  ],
  mode: 'development'
};

5. 4 生产环境下该做的第四件事::js语法检测 eslint ---统一代码书写规范

/*
        语法检查: eslint-loader  eslint
        //eslint-loader依赖于eslint
        //cnpm i  eslint-loader eslint -D
          注意:只检查自己写的源代码,第三方的库是不用检查的
          设置检查规则:
            在package.json中eslintConfig中设置~
              "eslintConfig": {
                "extends": "airbnb-base",
                "env": {
                  "browser": true // 支持浏览器端全局变量
                                  // 因为eslint不认识 window、navigator全局变量
                  }
              }

              
            airbnb风格指南(语言规范)需要的三个依赖包 --> 
            cnpm i eslint-config-airbnb-base eslint-plugin-import eslint  -D
            1.eslint-config-airbnb-base 
            2.eslint-plugin-import 
            3.eslint
*/



/*

!!!!!!!!!!!!!!!!直接加进js文件(注释//也要加的)
// eslint-disable-next-line// 下一行eslint所有规则都失效(下一行不进行eslint检查)

*/
  • 此时的页面 webpack.config.js的代码---运行webpack看效果

    const { resolve } = require('path');

    //引入插件'html-webpack-plugin' const HtmlWebpackPlugin = require('html-webpack-plugin');

    module.exports = { entry: './src/js/index.js', output: { // 自动创建build/js/built.js filename: 'js/built.js', path: resolve(__dirname, 'build') }, module: { rules: [ /* 语法检查: eslint-loader eslint //eslint-loader依赖于eslint //cnpm i eslint-loader eslint -D 注意:只检查自己写的源代码,第三方的库是不用检查的 设置检查规则: 在package.json中eslintConfig中设置~ "eslintConfig": { "extends": "airbnb-base", "env": { "browser": true // 支持浏览器端全局变量 // 因为eslint不认识 window、navigator全局变量 } }

            airbnb风格指南(语言规范)需要的三个依赖包 --> 
            cnpm i eslint-config-airbnb-base eslint-plugin-import eslint  -D
            1.eslint-config-airbnb-base 
            2.eslint-plugin-import 
            3.eslint
      */
      {
        test: /\.js$/,
        
        //排除node_modules文件
        exclude: /node_modules/,
        loader: 'eslint-loader',
        options: {
          // 自动修复eslint的错误
          fix: true
        }
      }
    ]
    

    }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }) ], mode: 'development' };

    !!!!!!!!!!!!!!!!直接加进js文件(注释//也要加的) // 下一行eslint所有规则都失效(下一行不进行eslint检查) // eslint-disable-next-line

5. 5 生产环境下该做的第五件事::js兼容性处理 babel ---代码兼容性处理

/*
        js兼容性处理:babel-loader @babel/core @babel/preset-env
        //cnpm i babel-loader @babel/preset-env @babel/core  -D
          1. 基本js兼容性处理 --> @babel/preset-env
            问题:只能转换基本语法,如promise等高级语法不能转换
          2. 全部js兼容性处理 --> @babel/polyfill  
          //cnpm i @babel/polyfill   -D   
          //@babel/polyfill不是插件可以在入口文件.js中直接import '@babel/polyfill'引入
            问题:我只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大了~
          3. 需要做兼容性处理的就做:按需加载  --> core-js
          //cnpm install  core-js  --save-dev
*/  
  • 此时的页面 webpack.config.js的代码---运行webpack看效果

    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') }, module: { rules: [ /* js兼容性处理:babel-loader @babel/core @babel/preset-env //cnpm i babel-loader @babel/preset-env @babel/core -D 1. 基本js兼容性处理 --> @babel/preset-env 问题:只能转换基本语法,如promise等高级语法不能转换 2. 全部js兼容性处理 --> @babel/polyfill
    //cnpm i @babel/polyfill -D
    //@babel/polyfill不是插件可以在入口文件.js中直接import '@babel/polyfill'引入 问题:我只要解决部分兼容性问题,但是将所有兼容性代码全部引入,体积太大了~ 3. 需要做兼容性处理的就做:按需加载 --> core-js //cnpm install core-js --save-dev */
    { 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' } } ] ] } } ] }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }) ], mode: 'development' };

5. 6 生产环境下该做的第六件事::压缩html和js文件

  • js压缩---当mode: 'production'时内置插件uglifyjsPlugin会自动压缩js代码

    webpack.config.js //运行webpack看效果

    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') }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html' }) ], // 生产环境下会自动压缩js代码 mode: 'production' };

  • html压缩---继续利用'html-webpack-plugin'

    webpack.config.js //运行webpack看效果

    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') }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', // 压缩html代码 minify: { // 移除空格 collapseWhitespace: true, // 移除注释 removeComments: true } }) ], mode: 'production' };

5. 1-6 生产环境下该做的事情大总结

webpack.config.js    //运行webpack看效果


const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

//压缩css代码
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');

//对html页面进行处理--直接通过new调用运行
const HtmlWebpackPlugin = require('html-webpack-plugin');

// 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';

// 复用loader
const 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',
    //需要引入 const { resolve } = require('path');
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        
        /**
         * use:['style-loader','css-loader']
         * 会将css文件整合到style样式中有缺陷
         * 所以引入const MiniCssExtractPlugin = require('mini-css-extract-plugin');
         * 会将css提取为单独文件并以link标签的形式插入
         * ==> use:[MiniCssExtractPlugin.loader,'css-loader']
         */

        /**
         * use:[
         *        MiniCssExtractPlugin.loader,
                  'css-loader',
                  {
                      // 还需要在package.json中定义browserslist
                      // 并且在 外层 定义nodejs环境变量:决定使用browserslist的哪个环境
process.env.NODE_ENV = 'production';

                      //browserslist的配置方式之一
                      "browserslist": {
                            "development": [
                              "last 1 chrome version",
                              "last 1 firefox version",
                              "last 1 safari version"
                            ],
                            "production": [
                              ">0.2%",
                              "not dead",
                              "not op_mini all"
                            ]
                                      },




                      // css兼容性处理
                      loader: 'postcss-loader',
                      options: {
                        ident: 'postcss',
                        //使用postcss里面的插件'postcss-preset-env'对css文件做处理
                        plugins: () => [require('postcss-preset-env')()]
                      }
                  }
         *    ]
         */
        

        use: [...commonCssLoader]
      },
      {
        test: /\.less$/,
        /**
         * 注意顺序!!!!!!
         * 顺序是'less-loader'先转为.css文件
         * 在执行'postcss-loader'做兼容性处理
         * 在执行'css-loader'将css代码写入js文件中
         * 再去执行MiniCssExtractPlugin.loader
         * 将css样式以link标签的方式引入页面
         */
        use: [...commonCssLoader, 'less-loader']
      },



      /*
        正常来讲,一个文件只能被一个loader处理。
        当一个文件要被多个loader处理,那么一定要指定loader执行的先后顺序:
          
          这里eslint和babel都要对js文件进行处理
          先执行eslint 在执行babel
      */


      {
        // 在package.json中eslintConfig --> airbnb

        /**
         *   "eslintConfig": {
         *             "extends": "airbnb-base",
         *             "env": {
         *                   "browser": true
         *                     }
         *     }
         */

        
        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'
    }),

    //只需要如此调用就可以压缩css代码无需再多余操作
    new OptimizeCssAssetsWebpackPlugin(),


    new HtmlWebpackPlugin({
      template: './src/index.html',
      //压缩html代码
      minify: {
        collapseWhitespace: true,
        removeComments: true
      }
    })
  ],
  //生产环境自动压缩js代码
  mode: 'production'
};

6.webpack新体验之性能优化配置

  • **开发环境性能优化
    **

优化打包构建速度

HMR

优化代码调试

source-map

  • **生产环境性能优化
    **

优化打包构建速度

oneOf

babel缓存

多进程打包

externals

dll

优化代码运行的性能

    **          缓存(hash-chunkhash-contenthash)**

tree shaking

code split

JS代码懒加载/预加载

pwa

6.1 开发环境优化

6.1.1 HRM

6.1.1 此时的目录结构为

配合WDS使用 npx webpack-dev-server

解答:为什么要引入HRM?
因为在WDS的作用下只要一个文件(模块(具体可以是一个.css/.js/...文件))改变会
浏览器会全部重新刷新渲染页面.如果项目模块十分的庞大,只修改一个模块,WDS会引发
全部重新刷新渲染页面,打包构建速度降低。

HMR: hot module replacement 热模块替换 / 模块热替换
    作用:一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块)极大提升构建速度
      
      样式文件:可以使用HMR功能:因为style-loader内部实现了~
      所以在开发环境中使用style-loader不是没有道理的
      
      
      js文件:默认不能使用HMR功能 --> 需要修改添加js代码,添加支持HMR功能的代码
            
        注意:HMR功能对js的处理,只能处理非入口js文件(这里是./print.js)的其他文件。
这      这里的入口文件是index.js

这里是页面./print.js的代码

因为  js文件:默认不能使用HMR功能 --> 需要修改添加js代码,添加支持HMR功能的代码才能使用HRM

if (module.hot) {
  // 一旦 module.hot 为true,说明开启了HMR功能。 --> 让HMR功能代码生效
  module.hot.accept('./print.js', function() {
    // 方法会监听 print.js 文件的变化,一旦发生变化,其他模块不会重新打包构建。
    // 会执行后面的回调函数
    print();
  });
}

这里是页面webpack.config.js的代码

重点在于 devServer 中 hot:true 的配置

开启HRM后的情景分析
1.修改样式文件页面会根据修改的样式文件信息只会重新渲染该样式文件,其他文件不受影响(style-loader)

2.修改js文件时默认触发WDS而不是HRM,需要添加相应的代码才能使HRM生效

3.修改html文件时,如果开启了WDS又开启HRM会使得WDS失效(不能动态更新html页面),
解决方案是修改entry入口,将html文件引入,重新唤醒WDS,不用做HRM功能

const { resolve } = require('path');

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  

  //(不需要做HMR功能)
  // 解决:修改entry入口,将html文件引入 
  entry: ['./src/js/index.js', './src/index.html'],


  output: {
    filename: 'js/built.js',
    path: resolve(__dirname, 'build')
  },
  module: {
    rules: [
      // loader的配置
      {
        // 处理less资源
        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: {
          limit: 8 * 1024,
          name: '[hash:10].[ext]',
          // 关闭es6模块化
          esModule: false,
          outputPath: 'imgs'
        }
      },
      {
        // 处理html中img资源
        test: /\.html$/,
        loader: 'html-loader'
      },
      {
        // 处理其他资源
        exclude: /\.(html|js|css|less|jpg|png|gif)/,
        loader: 'file-loader',
        options: {
          name: '[hash:10].[ext]',
          outputPath: 'media'
        }
      }
    ]
  },
  plugins: [
    // plugins的配置
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  mode: 'development',



  devServer: {
    contentBase: resolve(__dirname, 'build'),
    compress: true,
    port: 3000,
    open: true,
    // 开启HMR功能
    // 当修改了webpack配置,新配置要想生效,必须重新webpack服务
    hot: true
  }
};

6.1.2 source-map---开发环境下如何调试代码

/*
  source-map: 一种 提供源代码到构建后代码映射 技术 (如果构建后代码出错了,通过映射关系可以追踪源代码错误)

    [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

    source-map:外部
      错误代码准确信息 和 源代码的错误位置
    inline-source-map:内联
      只生成一个内联source-map--以base64的方式写在构建后输出的js代码中
      错误代码准确信息 和 源代码的错误位置
    hidden-source-map:外部----为了隐藏源代码而诞生的
      错误代码错误原因,但是没有错误位置
      不能追踪源代码错误,只能提示到构建后代码的错误位置
      (他的错误位置提示的是构建后输出的.js(或其他代码)中的错误位置,我们想要的错误位置是构建前的源代码错误位置)
    eval-source-map:内联
      每一个文件都生成对应的source-map,都在eval
      错误代码准确信息 和 源代码的错误位置
    nosources-source-map:外部----为了隐藏源代码而诞生的
      错误代码准确信息, 但是没有任何源代码信息
    cheap-source-map:外部
      错误代码准确信息 和 源代码的错误位置 
      只能精确到行(一整行中尽管有一句是错的它也会把一整行标红)
    cheap-module-source-map:外部
      错误代码准确信息 和 源代码的错误位置 
      module会将loader的source map加入

*/

比较

    内联 和 外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快

    开发环境:速度快,调试更友好
      速度快(eval>inline>cheap>...)
        eval-cheap-souce-map
        eval-source-map
      调试更友好  
        souce-map
        cheap-module-souce-map
        cheap-souce-map

      --> eval-source-map  / eval-cheap-module-souce-map

    生产环境:源代码要不要隐藏? 调试要不要更友好
      内联会让代码体积变大,所以在生产环境不用内联
      nosources-source-map 全部隐藏
      hidden-source-map 只隐藏源代码,会提示构建后代码错误信息
	
	
      --> source-map / cheap-module-souce-map

这里是页面 webpack.config.js 的代码

重点是  devtool: 'eval-source-map'  的配置

const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = { 
      devtool: 'eval-source-map'
};