• webpack使用详解


    什么是webpack

    官方定义:从本质上来说,webpack是一个现代的JavaScript的静态模块打包工具。
    webpack是前端工程化的一个解决方案。
    主要功能: 提供了前端模块化功能支持,模块混淆,代码压缩,处理浏览器JS兼容性,性能优化等强大功能。

    webpack前提

    学webpack的前提是要知道es6的模块化知识或者commonjs的知识(不用太深),两者都提供模块化功能。es6的模块化是官方标准,较新,将来一定是主流,commonjs比较早就有了,资历深。知道一个或者两个都知道比较好。没学过去看看,不然看不懂webpack例子。
    其他前提:
    javascript的es5基础 (不用太深)
    html (不用太深)
    css(不用太深)
    node.js(不用太深)

    webpack的安装

    webpack依赖node.js。没有的需要先安装node.js。就不说怎么安装了。

    安装webpack3.6.0这个版本。

    npm install webpack@3.6.0 -g
    
    • 1

    能看到版本号,就表示安装成功了。

    webpack -version
    
    • 1

    webpack的基本使用过程

    先把目录创建好,一个main.js文件,这是js的入口文件。dist文件夹是用来放打包后的文件,后面会用到。因为webpack是支持模块化的,所以加了一个mathUtil.js来简单模拟模块化。
    在这里插入图片描述
    main.js的代码如下:
    调用了mathUtils.js的代码,实现简单输出。第一行代码是commonjs的语法,不了解的只需要知道是这是在引用模块就可以了。

    const {add,mult}=require("./mathUtils.js")
    console.log(add(1,2))
    console.log(mult(1,2))
    
    • 1
    • 2
    • 3

    mathUtils.js定义了两个方法并且导出给别人使用。

    function add(a, b) {
        return a+b
    }
    
    function mult(a, b) {
        return a*b
    }
    
    //使用commonJs导出
    module.exports = {
        add,
        mult
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    index.html的内容为空,也就是默认的html文本,里面什么都没写。
    分析:
    现在我们有一个main.js,他引用了mathUtils.js里面的内容。
    js有了,那么我们是不是要在js里面引用呢?答案是不要。如果不用webpack,我们可能就会引用多个js文件,比如main.js和mathUtils.js,当然你可能有很多个js文件,都引用也非常的麻烦。webpack可以将这些js文件打包成一个文件。然后你只需要引入打包好的这一个文件就行了,打包也非常的简单。
    执行下面的代码,会在dist目录下面生成一个bundle.js文件,这就是打包好的文件,注意这里我们打包的时候只写了main.js,webpack会帮我们把相关联的js文件全部打包进来。这就是webpack帮我们简化步骤的地方,和我们一个个手动引用相比,这里相当于变成了自动引用,我们只需要提供入口js,也就是我们的main.js这一个js文件就可以了。

    webpack ./src/main.js ./disk/bundle.js
    
    • 1

    我们简单看一下生成的这个bundle.js。前面的代码不用看,主要看后面的几行,后面那几行实际上就是把main.js和mathUtils.js的代码合并带一起了,还有一些commonjs的代码,这些代码浏览器还是不识别的,前面生成的一堆看不懂的代码就是给commonjs做支持用的。

    /******/ (function(modules) { // webpackBootstrap
    /******/ 	// The module cache
    /******/ 	var installedModules = {};
    /******/
    /******/ 	// The require function
    /******/ 	function __webpack_require__(moduleId) {
    /******/
    /******/ 		// Check if module is in cache
    /******/ 		if(installedModules[moduleId]) {
    /******/ 			return installedModules[moduleId].exports;
    /******/ 		}
    /******/ 		// Create a new module (and put it into the cache)
    /******/ 		var module = installedModules[moduleId] = {
    /******/ 			i: moduleId,
    /******/ 			l: false,
    /******/ 			exports: {}
    /******/ 		};
    /******/
    /******/ 		// Execute the module function
    /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    /******/
    /******/ 		// Flag the module as loaded
    /******/ 		module.l = true;
    /******/
    /******/ 		// Return the exports of the module
    /******/ 		return module.exports;
    /******/ 	}
    /******/
    /******/
    /******/ 	// expose the modules object (__webpack_modules__)
    /******/ 	__webpack_require__.m = modules;
    /******/
    /******/ 	// expose the module cache
    /******/ 	__webpack_require__.c = installedModules;
    /******/
    /******/ 	// define getter function for harmony exports
    /******/ 	__webpack_require__.d = function(exports, name, getter) {
    /******/ 		if(!__webpack_require__.o(exports, name)) {
    /******/ 			Object.defineProperty(exports, name, {
    /******/ 				configurable: false,
    /******/ 				enumerable: true,
    /******/ 				get: getter
    /******/ 			});
    /******/ 		}
    /******/ 	};
    /******/
    /******/ 	// getDefaultExport function for compatibility with non-harmony modules
    /******/ 	__webpack_require__.n = function(module) {
    /******/ 		var getter = module && module.__esModule ?
    /******/ 			function getDefault() { return module['default']; } :
    /******/ 			function getModuleExports() { return module; };
    /******/ 		__webpack_require__.d(getter, 'a', getter);
    /******/ 		return getter;
    /******/ 	};
    /******/
    /******/ 	// Object.prototype.hasOwnProperty.call
    /******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
    /******/
    /******/ 	// __webpack_public_path__
    /******/ 	__webpack_require__.p = "";
    /******/
    /******/ 	// Load entry module and return exports
    /******/ 	return __webpack_require__(__webpack_require__.s = 0);
    /******/ })
    /************************************************************************/
    /******/ ([
    /* 0 */
    /***/ (function(module, exports, __webpack_require__) {
    
    const {add,mult}=__webpack_require__(1)
    console.log(add(1,2))
    console.log(mult(1,2))
    
    /***/ }),
    /* 1 */
    /***/ (function(module, exports) {
    
    function add(a, b) {
        return a+b
    }
    
    function mult(a, b) {
        return a*b
    }
    
    //使用commonJs导出
    module.exports = {
        add,
        mult
    }
    
    /***/ })
    /******/ ]);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    最后,只需要在index.html里面引用我们生成的bundle.js就可以了。

    <script src="./dist/bundle.js"></script>
    
    • 1

    打开浏览器是可以看到js的执行输出的。
    在这里插入图片描述

    webpack的配置

    前面我们使用webpack打包的时候,是手动指定路径的,这些东西可以写到配置文件里面,方便我们管理。

    webpack ./src/main.js ./disk/bundle.js
    
    • 1

    需要在项目根目录下创建webpack.config.js文件。这是webpack的配置文件,默认就叫这个名字。
    在这里插入图片描述
    写入下面的内容,然后在终端执行webpack这个命令,不用加任何参数,这时候会报错,告诉你要用绝对路径。实际上,下面path的写法是不对的,需要绝对路径,我们直接写不合适,而是通过node.js提供的path包来获取。

    module.exports = {
        entry:"./src/main.js",
        output:{
            path:"./dist",
            filename:"bundle.js"
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    默认情况下是没有path这个包的。我们需要将项目初始化为node工程。
    提供下面的命令初始化node工程。要在index.html的父目录执行。

    npm init
    
    • 1

    会叫你填一些值,不要写中文,不是中文的一直默认就可以,后面会说具体配置。
    完成之后会多出一个package.json的文件,这是node的配置文件。
    里面的内容大致如下。

    {
      "name": "meetwebpack",
      "version": "1.0.0",
      "description": "",
      "main": "main.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "",
      "license": "ISC"
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述
    现在就可以使用node提供的path库了。
    通过require引入库,通过path.resolve方法获取绝对路径,__dirname是path库提供的项目路径

    const path=require("path")
    module.exports = {
        entry:"./src/main.js",
        output:{
            path:path.resolve(__dirname,"dist"),
            filename:"bundle.js"
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    现在我们可以直接使用webpack来打包,而不用指定路径了。
    在这里插入图片描述

    前面的方式运行webpack已经可以用了。但是还有一种更好的方式。那就是使用node的脚步运行webpack。
    前面的问题是我们可能存在多个webpack配置文件,一个是生产环境的一个是开发环境的,那么如果环境变了,我们的webpack打包命令需要指定配置文件。
    前面没有指定配置文件名称是因为默认配置文件名称就叫做webpack.config.js。

    webpack production.config.js
    
    • 1

    我们可以使用一种更灵活的方式,就是把这些命令配置到脚本里面。下面的命令就是运行build这个脚本,这个脚本是我们自己定义的。

    npm run build
    
    • 1

    在我们的package.json里面有下面的脚本。我们可以在这里面创建我们自己的build脚本,默认写了一个叫test的脚本。

      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack"
      }
    
    • 1
    • 2
    • 3
    • 4

    现在执行npm run build可以实现和原来一样的效果。
    在这里插入图片描述
    这里还存在一个问题,就是我们在终端执行命令的时候,调用的都是全局的webpack命令。这就会造成问题,因为实际项目中,本地和全局可能因为某些原因需要使用不同的版本。都用全局就会造成问题。
    这时候我们需要安装一个本地版本就可以了。

     npm install webpack@3.6.0 --save-dev
    
    • 1

    执行完后会多出下面的目录。node_modules包含了node的所有模块,有几百个,webpack就在里面。
    默认在终端执行webpack都是执行全局的node,除非写成下面的样子

    ./node_modules/webpack xxxxx
    
    • 1

    当然现在我们有更好的方式,执行下面的代码就可以了,这就是最终的效果。

    npm run build
    
    • 1

    在这里插入图片描述
    并且package.json会多出下面的节点。

      "devDependencies": {
        "webpack": "^3.6.0"
      }
    
    • 1
    • 2
    • 3

    webpack配置CSS

    我们先创建css,目录并且添加normal.css文件,内容如下。

    body{
        background-color: lightgreen;
    }
    
    • 1
    • 2
    • 3

    调整一下js文件结构,把作为入口的main.js暴露再外面。
    在这里插入图片描述

    这时候我们不要在html中引入css代码了,而是交给webpack来做。

    webpack本身并没有支持CSS的功能,这些功能通过loader来提供。
    我们只需要加载对应的loader,就可以实现对应的功能。
    webpack提供非常多的loader,CSS loader只是其中一个。

    我们打开文档:
    https://www.webpackjs.com/loaders/#%E6%A0%B7%E5%BC%8F

    我们需要用到的css loader就两个,一个是css-loader,用于解析css代码,并返回css代码。如果只单独用这个loader是没有效果的,因为这个loader只负责加载,不负责导出显示到dom中。所以我们还需要一个style-loader模块,这个模块就是专门干这个事的。
    在这里插入图片描述
    安装模块,webpack 3.6.0对应的0.9.0是可以使用的,太高版本会给警告。
    使用npm好像是会直接报错的,但是cnpm只有警告,并且给出提示说当前版本只能对应的版本范围。

    npm install --save-dev css-loader@0.9.0
    npm install style-loader@0.9.0 --save-dev
    
    • 1
    • 2

    然后需要在配置文件里面添加module节点,并添加rules的内容。
    需要注意的是,use里面的两个loader是后面的先加载,顺序错了是会报错的,文档里面有这么说。不知道为什么这样设计。

    const path=require("path")
    module.exports = {
        entry:"./src/main.js",
        output:{
            path:path.resolve(__dirname,"dist"),
            filename:"bundle.js"
        },
        module: {
            rules: [
                {
                    test: /\.css$/,
                    use: [
                        { loader: "style-loader" },
                        { loader: "css-loader" }
                    ]
                }
            ]
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这时候执行下面的代码再运行index.html就可以看到css的样式了

    npm run build
    
    • 1

    如果背景色变了就表示成功了。

    webpack配置less

    less的配置和css的配置是类似的。
    这里存在一个困难是版本问题,你根本不知道什么版本和你的webpack匹配。
    而且版本号是没有统一的,一个loader是一个独立的版本号。
    解决办法就是到github直接搜索你要安装的loader,比如这里的less-loader,随便点击一个tag版本。查看里面的package.json,里面是可以查看到webpack的版本范围的。
    对于任意的loader都是类似的,这些loader都是webpack官方发布的。
    使用下面的版本对应webpack3.6.0是可以的,只是会告诉你已经废弃,math方法有bug。实际项目还是不要用了,应该升级webpack版本。

    npm install --save-dev less-loader@5.0.0 less@2.3.1
    
    • 1

    在webpack.config.js下面的rules节点下面添加下面的代码。

    {
                    test: /\.less$/,
                    use: [{
                        loader: "style-loader" // creates style nodes from JS strings
                    }, {
                        loader: "css-loader" // translates CSS into CommonJS
                    }, {
                        loader: "less-loader" // compiles Less to CSS
                    }]
                }    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    创建css文件夹,在里面准备我们的special.less测试文件。
    在这里插入图片描述

    @fontSize:50px;
    @fontColor:lightblue;
    body{
      font-size: @fontSize;
      color: @fontColor;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在main.js中引用less

    require("./css/special.less")
    
    • 1

    在index.html中添加如下内容:

    <div id="box">
      Hello Webpack
    </div>
    
    • 1
    • 2
    • 3

    最后运行。

    npm run build
    
    • 1

    效果正确就表示配置成功了。

    webpack对于图片的处理

    图片也是需要loader的,在webpack里面图片分为两种情况,在配置文件里面可以配置一个limit属性来判断图片大小是否超过这个指,如果小于这个值,就会被当做base64来处理,如果大于这个值,就当正常的图片文件来处理。
    版本一定要写1.1.2,1.0.0是不能显示图片的,对于webpack3.6.9。

    npm install --save-dev url-loader@1.1.2
    
    • 1

    这里的关键点是多了一个limit,也就是我们上面说的图片大小限制。

    {
            test: /\.(png|jpg|gif)$/,
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 8192
                }
              }
            ]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    引入两张图片,gun.jpg的大小为4kb,baidu.png的大小为15kb.。在这里插入图片描述

    把body的背景指定为gnu.jpg,因为图片大小小于limit,所以图片会以base64的形式传递。

    body{
        /*background-color: lightgreen;*/
        background: url("../img/gnu.jpg");
    }
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    执行下面代码,就可以看到效果了。

    npm run build
    
    • 1

    在这里插入图片描述
    如果把图片换成baidu.jpg,就会直接报错。告诉你找不到file-loader。前面讲过,webpack处理图片有两种方式,当图片大小小于limit的时候采用的是base64的字符串方式。这时候就需要用到url-loader,而当图片大于limit的时候,就不能用url-loader,而是要用file-loader.

    Module build failed: Error: Cannot find module 'file-loader'
    
    • 1

    下载file-loader。

     npm install file-loader@2.0.0 --save-dev
    
    • 1

    配置file-loader。
    前面的url-loader是基于file-loader实现的,两者只能写其中一个,同时写是不能生成图片的。
    前面的url-loader是基于file-loader实现的,两者只能写其中一个,同时写是不能生成图片的。
    前面的url-loader是基于file-loader实现的,两者只能写其中一个,同时写是不能生成图片的。

    {
            test: /\.(png|jpg|gif)$/,
            use: [
              {
                loader: 'file-loader',
                options: {}
              }
            ]
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    编译运行后发现图片不显示。但是dist目录下是生成了图片的。
    在这里插入图片描述
    我们看下浏览器body的url地址,路径是不对的,应该在前面加一个dist/。这是可以提供配置实现的。

    url(d9c8750bed0b3c7d089fa7d55720d6cf.png)
    
    • 1

    需要子啊webpack配置文件里面添加publicPath这个节点。

        output:{
            path:path.resolve(__dirname,"dist"),
            filename:"bundle.js",
            publicPath:"dist/"
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5

    现在baidu.jpg就可以被当做图片显示了。
    我们不太可能将所以图片都放在dist根目录下,给dist创建一个img目录是比较合理的,可以提供下面的代码实现。[name]表示原来的文件名[hash:8]表示8位hash值,不写默认32位,[ext]表示扩展名。这样就非常的工程化了。

    options: {
           name:"img/[name]-[hash:8].[ext]"
    }
    
    • 1
    • 2
    • 3

    输出效果:
    在这里插入图片描述

    将ES6语法转成ES5语法

    webpack的一个最大的优点就是他帮我们做了一些兼容性问题的处理。可以通过babel-loader来实现。

    npm install babel-loader@8.0.0 @babel/core @babel/preset-env
    
    
    • 1
    • 2

    在webpack配置文件里面添加下面内容:

    {
          test: /\.js$/,
          exclude: /(node_modules|bower_components)/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env']
            }
          }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    观察输出的js文件,之前的const等这些es6语法就都转化成es5的语法了。

  • 相关阅读:
    WPF中 ContextMenu 寻找父物体的一种方案
    Orin 调试GMSL camera 96712手册重点
    分布式是什么?
    golang切片和数组拷贝(浅拷贝和深拷贝)
    Mygin中间件优化及logger日志中间件
    BeanNameViewResolver类简介说明
    P1825 [USACO11OPEN]Corn Maze S——bfs
    MySQL基础进阶:汇总数据
    人机组队概念的战场应用
    OpenCV(四十五):ORB特征点
  • 原文地址:https://blog.csdn.net/ScottePerk/article/details/126676076