webpack重难点知识梳理

239 阅读7分钟

webpack的基本概念


wepack产生的原因

传统的前端开发模式一般是开发人员直接书写html、css、和js等等各种代码,将用户请求的文件真实地放在服务器上。由于上述三种语言是弱类型语言,没有模块化概念代码不能复用,没有作用域的概念,存在变量空间污染的情况,导致传统的开发方式过程十分复杂、工作量巨大,经常要编写重复性的代码,并且各种代码互相混杂可读性差。

如果前端开发可以借鉴C++和Java等语言的模块化开发理念,将各种html、css、js和图片等资源抽象成一个个互相独立的功能模块,从而让开发人员像搭积木一样开发前端页面,就可以大大减轻开发人员工作量,并且使代码的可读性、规范性和美观性增强。

webpack如何工作

基于模块化开发需求,人们又制定了CommonJS等模块化标准,让开发者可以以模块化的方式开发,对变量、函数和各种资源进行导入导出。

但是,通过模块化方式编写的代码,浏览器是不能直接识别的,比如import、export命令和vue文件。webpack是一款打包工具,就是为了解决这个问题。它是一个node.js应用程序,利用Google V8引擎的高效能帮开发者自动处理各种依赖,把各种模块文件(js、css、图片、json等文件)打包成浏览器能够识别的代码。

webpack程序只需要指定一个入口文件即可,webpack会解析这个入口文件,寻找所有它依赖的所有文件。经过webpack打包以后,这些代码就会被转译为浏览器能识别的程序。当然,随着人们研究的深入,webpack还提供了丰富的加载器和插件,实现了babel等一些列强大的功能。

一套典型的经过webpack打包之后的最终代码由一个index.html文件、若干bundle.js文件(有可能被切割成一个个小的代码段)和资源文件夹构成。也就是说,最终呈现给用户的是这些文件。

总之,webpack让前端开发具有工程性特点,让前端开发更优雅,大大提高了开发效率。

webpack的依赖环境


node.js运行环境

npm必须安装

webpack的安装


webpack 尽量使用本地安装。 安装方法:npm install –save-dev webpack

webpack的模块化开发的主要步骤


  • 编写模块库,并用CommonJS或者ES6风格导出。

    // lib.js
    function add (num1 , num2){
        return num1 + num2;
    }
    function multi(num1 , num2){
        return num1 * num2;
    }
    const globalSettings = {
    	appName: 'XX',
    	appOpen: true
    }
    // 导出函数和变量
    module.exports = {
        add,multi,globalSettings
    }
    
  • 在需要使用这些模块库方法的地方导入。例如,在math.js文件内:

const {add, globalSettings} = require('./lib.js')
console.log(add(1,3))
consoele.log(globalSettings.appName)
  • 需要一个入口js文件,将所有功能模块组织起来,形成一个完成的应用,他也是使用导入的方式。一般是main.js。有点像C++ 命令行程序里的main函数。

    const { add,multi } = require('./lib.js');
    console.log(add(1,2));
    console.log(multi(1,2));
    
  • 目前以上程序浏览器是执行不了的。使用webpack命令打包mian.js,像是C++语言的编译语法,后面的参数可以写在webpack.config.js里。webpack main.js obj.js

    这样,webpack将会自动处理main.js程序里的依赖,自动找到需要导入的依赖(无论多复杂),然后编译出一个浏览器可以识别的脚本obj.js

  • 在实际程序中链接目标文件,就像C++的连接器,浏览器就会识别并执行obj.js里面的程序。

    <script src="obj.js"></script>
    

webpack.config.js文件使用方式


  • webpack.config.js文件是很重要的配置文件,它是webpack命令默认调用的配置文件,因此在实际打包过程中只需要输入webpack就可以。

  • webpack.config.js文件内规定了入口文件、出口文件和其他一些重要参数。

  • webpack.config.js文件的出口文件需要用绝对路径来定位:

    // 先引入path包,全局包,不需要指定路径
    const path = require('path');
    // web.config.js实际上也是个包,需要使用模块方法输出配置信息
    module.exports = {
        entry : './src/main.js', 
    // 指定入口文件,不需要绝对路径
        output : { 
    // 需要使用对象的方式指定出口文件的路径        
    		path : path.resolve(__dirname, './dist'),        
    		filename : 'bundle.js'
     }
    }
    
  • npm run命令。它读取package.json配置文件的scripts字段记录的命令,便于记住较长或者的webpack命令。它优先调用本地程序包或者命令。例如webpack命令,可以优先调用本地webpack。

webpack的loader


  • css loader【2021.9.4在webpack 5.51.2上测试,css-loader和style-loader貌似不需要url-loader,也可以处理图片了】

    先安装两个loder:npm install –save-dev css-loader style-loader

    在webpack.config.js中调用loader

    module.exports = {
      module: {
        rules: [
          {
            test: /\.css$/i, 
           // 需要用到两个loader,css-loader负责载入css文件,而style-loader负责将css加载到dom
            use: ["style-loader", "css-loader"],
          },
        ],
      },
    };
    然后运行webpack在代码中导入css
    // 两种方式引入
    import css from './style.css';
    // 或者
    require('./style.css');
    // 或者这种方式,比较常见
    import './style.css'
    
  • 资源 loader(url)

    可以在webpack.config.js中设置limit,超过这个limit的资源将会被打包成资源;没有超过的,被解析成base64字符串。[新版Webpack已经不需要这样了]

    安装loader: npm install --save-dev url-loader

    在webpack.config.js中调用loader:

    module.exports = {
    module: {
       rules: [
           test: /\.(jpg|png|gif)/,
           type: 'javascript/auto',
    //解决编译通过无法加载文件的问题
           use: [
           {
              loader: 'url-loader',
              options: {
              limit:1024,
              esModule:false
    //解决编译通过无法加载文件的问题
           }
           }
          ]
       ]}
    };
    
    • 还要安装file-loader(会被url-loader自动调用)npm install file-loader

    • 打包出来的文件会被放到dist文件夹,为了让index.html文件正确调用它,需要在webpack.config.js中对publicPath进行配置:

      module.exports = {
          output:{
              paht: path.resolve(__dirname,'dist'),
              filename: obj.js,
              publicPath: 'dist/'
       }}
      
    • 打包编译正确后,还要解决一个问题,由于Webpack5已经弃用了url-loader和file-loader,因此继续使用以上两个loader将会出现文件重复打包、无法打开的问题,要解决以上问题,需要在规则里增加两个选项,以下是该办法的完整代码:

          module:{
              rules:[
                  {
                      test: /\.(png|jpg|gif|jpeg)$/,
                      use: [
                        {
                          loader: 'url-loader',
                          options: {
                            limit: 8192,
                            esModule:false
                          }
                        }
                      ],
                      type: 'javascript/auto'
                    }
               ]
          }
      
  • vue文件的处理

    • 安装两个loader:npm install vue-loader vue-template-compiler --save-dev

    • 在webpack.config.js中配置

      module.exports = {
          module: {
              rules:[
                  {
                      test: /\.vue$/,
                      use: ['vue-loader']
                  }
              ]
          }
      }
      
    • 从14版本的vue-loader开始,要使用vue-loader,还需要另外配置插件,否则在打包的过程中会有错误提示。在webpack.config.js文件内配置相应的插件:

    const VueLoaderPlugin = require('vue-loader/lib/plugin')
    module.exports = {
            // ...
            plugins:[
    	new VueLoaderPlugin()
            ]
    }
    

让webpack支持.vue文件


.vue格式文件是Vue.js开发出来的单文件组件(SFC)格式。它将一个组件封装一个单独的文件内,不用在引号内书写模板,实现了完整而漂亮语法高亮、CommonJS 模块、组件作用域的 CSS。要使.vue文件被正常解析和运作,需要webpack等打包工具进行编译。

Untitled.png

首先,安装vuenpm install vue –save

然后,在代码内直接导入vue:import Vue from ‘vue’

解决运行时提示错误:在webpackconfig.js的module.exports代码内中使用alias命令:

  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
			 // 用 webpack 1 时需用 'vue/dist/vue.common.js'
    }  }
💡 vue 2.x 不要安装最新版本的 vue-loader。解决方案:出现提示后安装 vue-loader@15 即可。

使用webpack-dev-server搭建本地调试服务器


webpack的编译过程是比较慢的,当代码规模较大的时候,如果采取传统的调试方式,每次修改代码后,重新构建所有代码查看修改效果,是需要花费漫长的时间。更加难受的是,程序员一般习惯于修改一点代码后就要查看效果,这样反复的构建和等待,将十分烦恼。为了解决这个问题,基于node.js的express框架开发的webpack-dev-server出现了。它的运行原理是,在本地搭建一个临时服务器,将编译结果存放在内存里。调试服务器从内存读写编译结果,这就大大加快了读写速度。同时,它监听用户修改,只编译修改的部分,用户修改后就能快速、实时看到修改结果。

版本重大更新。4.0.0版本以后的webpack-dev-server的配置方式发生了较大变化,contentBaseinline等选项不再有的,取而代之的是static对象(需要用path来拼接出绝对路径,directory属性)。inline属性不再需要了,默认是实时更新的。以下是在webpack.config.js文件内简单的配置信息:

module.exports = {
devServer: {
        static: {
            directory: path.join(__dirname, 'dist'),
          },
        port: 9923
    }
}

webpack配置文件的分离


对于不同编译模式(生产模式、开发模式)下,webpack.config.js文件内所生效的配置不尽相同。为了便于管理,将不同编译模式所需要的的配置的内容进行归类。在实际编译或者调试的时候,再通过合并工具构建所需要的配置文件。当工程代码规模庞大的时候,这种分类方式是很有必要的。掌握这个知识,有利于理解脚手架的配置原理。使用方法如下:

  1. 首先,需要安装一个webpack-merge包。npm install -D webpack-merge

  2. 然后将不同配置进行抽离。将公共部分放在一个配置文件里(baseConfig.js),将体现不同特性的配置放在不同的配置文件里。在个性化配置文件内,将公共配置文件导入、合并,然后输出:

    // 先导入工具包
    const merge = require('webpack-merge')
    // 再导入公共配置文件
    const  baseConfig = require('./baseConfig.js')
    // 合并并输出
    module.exports = merge.merge( baseConfig, devConfig)
    
    💡 要注意的是,^5.8.0版本的webpack-merge做了修改,输出的内容是对象,因此需要采取对象的方式导入,不能使用{}。使用的时候,需要用这个对方的merge方法。
  3. 在package.json文件的scripts字段配置不同的命令,以显示指示webpack调用不同的配置文件,而不是调用默认的webpack.config.js。如下面的方法:

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack --config pro.config.js",
        "dev": "webpack-dev-server  --config dev.config.js --open"
      },