Webpack入门教程

4,008 阅读9分钟

什么是Webpack

通俗一点来说Webpack是一个前端打包工具,它可以将我们项目中的所有js、图片、css等资源,根据其入口文件的依赖关系,打包成一个能被浏览器识别的js文件。能够帮助前端开发将打包的过程更智能化和自动化。

一个基本的webpack配置:

module.exports={
    entry:,//设置入口文件
    output:{},  //设置输出文件
    module:{    //设置loader,即一些资源转换工具
        rules:[]
    },     
    plugins:[],  //设置插件,插件能做到很多loader做不到的事情
}

其中的entry是设置入口文件,webpack会根据其入口文件的依赖关系,将所有依赖关系的资源打包在一起。output是设置打包后文件的输出,例如:打包后的文件名和输出路径等。module是设置loader,即设置一些资源转换工具,例如将stylus、less、sass进行处理,转换成浏览器能够识别的css资源。plugins是设置插件的地方,官方也提供了很多插件,插件能够帮助我们做很多事情,例如压缩打包等,官方也为我们提供了插件的文档

开始前的准备

第一步安装webpack

首先我们可以通过npm全局安装一下webpack,接着我们新建一个文件夹,命名为:webpack-demo

//全局安装
npm install -g webpack

将终端切换到webpack-demo下执行下面的语句,将webpack安装到webpack-demo目录下。

npm install --save-dev webpack

第二步创建package.json文件

通过终端进入webpack-demo目录下,然后执行npm init命令,终端会咨询你一些npm的配置,例如项目名称、作者等。在这里,我们仅仅为了演示和学习,一路回车即可。

这时候我们就自动生成了一个webpack.json的文件,我们可以通过这个文件看到当前的自动化脚本和项目的依赖等信息。

第三步编写webpack.config.js

在编写webpack.config.js之前,为了方便学习演示,我们先创建几个文件夹:

build-用来存放打包后的资源

html-用来存放html文件

js-用来存放js文件

我们在html文件夹下,创建一个index.html文件,在这个文件中我们要引用稍后通过webpack打包好的js资源,并进行效果的展示。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Hello Webpack</title>
</head>
<body>
    <div id="root"></div>
    <script type="text/javascript" src="../build/bundle.js"></script>
</body>
</html>

这里面我们在body中编写了一个id为root的div,稍后我们会通过js代码,在root下添一个div标签,其内容是:Hello Webpack!。紧接着,我们引入了一个script标签,它的资源引用指向build文件夹下的bundle.js文件(我们会在webpack输出配置中配置输出的文件名,这个稍后就会讲)。

接着我们在js文件夹下面新建一个index.js文件:

index.js

var domDiv=document.createElement("div");
domDiv.textContent="Hello Webpack!"
var root=document.querySelector("#root");
root.appendChild(domDiv);

在这里,我们在id为root的标签下,添加了一个内容为:Hello Webpack!的div标签。

到这里,我们终于把前期工作都准备完毕了,我们在webpack-demo的文件夹下,创建webpack.config.js的文件,正式开始我们的webpack之旅!

webpack.config.js

module.exports={
    /**
     * 单入口文件打包
     */
    entry:__dirname+"/js/index.js",   //入口文件,即webpack开始打包的入口
    output:{
        path:__dirname+"/build",   //打包出口文件路径
        filename:"bundle.js"       //打包后文件名,这里我们将打包后的文件名设置成bundle,即index.html中引用的文件名
    }
}

在这里通过CommonJS语法规范,导出了一个对象。首先我们先看entry的属性。

entry

entry主要用来设置打包文件的入口,即webpack从哪个文件开始进行打包,webpack会不断寻找其依赖关系,将所有依赖的文件打包在一起。

在这里我们将入口文件设置成:__dirname+"/js/index.js",即项目目录下的js文件夹下的index.js文件,对它进行打包。

entry还可以配置多入口文件,这个会在下面讲解,多入口文件的情况。

output

output主要用来设置文件输出的路径和文件名,我们通过path设置了文件打包输出的目录,即项目目录下的build文件夹。通过filename设置了文件输出的名字,即bundle.js,这也是我们在index.js下等待引用的文件名。

开始打包

完成了最简单的webpack配置,接着我们在终端输入webpack进行打包。

在这个过程中可能会遇到 One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:的提示,我们根据提示输入webpack-cli即可,它就会自动替我们下载webpack-cli。

打包完成后,我们的目录结构为:

在build文件下面多了一个bundle.js文件,即webpack替我们打包后生产的文件。

然后我们在浏览器中打开index.html即可发现我们浏览器中显示了:Hello Webpack!

多入口文件打包

有时候我们的入口文件可能不止一个,例如我们在js目录下,再新建一个greeter.js的文件。

greeter.js

var domGreet=document.createElement("div")
domGreet.textContent="Welcome to learn Webpack";
var root=document.querySelector("#root");
root.appendChild(domGreet);

依旧是在root下增加一个子元素,子元素的内容为Welcome to learn Webpack

接着我们修改index.html文件:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Hello Webpack</title>
</head>
<body>
    <div id="root"></div>
    <script type="text/javascript" src="../build/bundle.js"></script>
    <script type="text/javascript" src="../build/greeter.js"></script>
</body>
</html>

我们在index.html中多引入了一个名为greeter.js的资源。

接着,我们修改webpack.config.js文件:

module.exports={
    /**
     * 多入口文件打包
     */
    entry:{
        bundle:__dirname+"/js/index.js",   //入口文件,即webpack开始打包的入口
        greeter:__dirname+"/js/greeter.js"
    },
    output:{
        path:__dirname+"/build",   //打包出口文件路径
        filename:"[name].js"       //打包后文件名,如果是多入口,引用[name],会将entry的对象中的属性作为文件名
    }
}

这时候entry的值是一个对象,通过属性和值的方式定义多个入口文件,我们在outputfilename值中引用[name],就会把entry中的属性名作为文件的名字,打包输出。

这时候我们的build文件下就会存在两个打包后的js文件:bundle.jsgreeter.js文件。

这时候我们再打开index.html文件,显示如下:

Loader

Loader主要是用来对文件资源进行转换打包,例如:我们js中运用了es6的语法,而有的浏览器不支持,我们就可以用babel将es6的语法转换成浏览器支持的es5语法。

在这里我们主要通过运用url-loader对图片资源进行打包,演示一下loader的作用。

我们准备了一图片:

pic01.jpg

我们新建一个文件夹,命名为image。将图片放在这个目录下。

我们修改index.js文件,新建一个img标签,显示该图片,并将标签加到id为root的div下。

var domDiv=document.createElement("div");
domDiv.textContent="Hello Webpack!"
var root=document.querySelector("#root");
root.appendChild(domDiv);

var image=document.createElement("img");
image.src=require('../image/pic01.jpg');
root.appendChild(image)

这时候如果我们直接执行webpack进行打包,会发现会报错:You may need an appropriate loader to handle this file type.

这是因为webpack不知道用什么loader去转换打包我们的图片资源。所以接着我们修改我们的webpack.config.js文件。

webpack.config.js

module.exports={
    /**
     * 单入口文件打包
     */
    //  entry:__dirname+"/js/index.js",   //入口文件,即webpack开始打包的入口
    /**
     * 多入口文件打包
     */
    entry:{
        bundle:__dirname+"/js/index.js",   //入口文件,即webpack开始打包的入口
        greeter:__dirname+"/js/greeter.js"
    },
    output:{
        path:__dirname+"/build",   //打包出口文件路径
        filename:"[name].js",       //打包后文件名,如果是多入口,引用[name],会将entry的对象中的key作为文件名
        publicPath:"./"
    },
    module:{
        rules:[
            {
                test: /\.(png|jpg)?$/,
                use:[
                    {
                        loader:"url-loader",
                    }
                ]
              },
        ]
    }
}

在这里,我们增加了module,在这里我们在rules数组中添加我们的规则,例如在这里我们添加了一个规则:

在遇到png或jpg结尾的文件后缀时,我们loader运用url-loader去转换。

好了,写完这个后,我们接着利用npm去安装一下url-loader,我们可以修改packge.json文件:

package.json

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.16.2",
    "webpack-cli": "^3.1.0",
    "url-loader":"1.0.1"
  }
}

然后在终端运行npm install,npm就会自动帮我安装url-loader。接着我们通过webpack命令进行打包。

打包完成后,我们运行index.html文件,我们可以看到图片就被加载到页面中了:

通过options 对loader进行设置配置

我们可以通过options对loader进行设置配置参数,例如我们可以发现,我们上面这个利用url-loader进行转换后的图片资源是被转换成了base64的形式引用的。

接下来,我们运用通过给url-loader增加配置参数,限制一个文件的阈值,当大于这个阈值时,将文件交给file-loader进行打包处理。

我们修改package.config.js文件

package.config.js

module.exports={
    /**
     * 单入口文件打包
     */
    //  entry:__dirname+"/js/index.js",   //入口文件,即webpack开始打包的入口
    /**
     * 多入口文件打包
     */
    entry:{
        bundle:__dirname+"/js/index.js",   //入口文件,即webpack开始打包的入口
        greeter:__dirname+"/js/greeter.js"
    },
    output:{
        path:__dirname+"/build",   //打包出口文件路径
        filename:"[name].js",       //打包后文件名,如果是多入口,引用[name],会将entry的对象中的key作为文件名
        publicPath:"./"
    },
    module:{
        rules:[
            {
                test: /\.(png|jpg)$/,
                use:[
                    {
                        loader:"url-loader",
                        options:{
                            limit:8194,
                            publicPath:"../build"
                        }
                    }
                ]
              },
        ]
    }
}

在这里我们通过给url-loader添加配置参数,设置limit为8194,即当图片文件小于8194字节的时候,会通过url-loader对图片进行base64的转换;而当大于8194字节时,图片会被file-loader转换,转成以资源路径的形式引用。

由于我们打包出来的资源都在build文件目录下和index.html不在同一个目录下,所以我们通过publicPath配置,在js引用图片资源时,路径指向build文件夹下。

Plugins

Plugins我们可以通过它,给项目配置很多的插件。

webpack也为我提供了完整的插件文档:插件文档

在这里我们主要使用BannerPlugin给每个打包后的js文件添加banner文字头,来举例学习Plugins的作用。

BannerPlugin文档

根据文档我们发现使用BannerPlugin很简单,我们修改webpack.config.js文件

webpack.config.js


module.exports={
    /**
     * 单入口文件打包
     */
    //  entry:__dirname+"/js/index.js",   //入口文件,即webpack开始打包的入口
    /**
     * 多入口文件打包
     */
    entry:{
        bundle:__dirname+"/js/index.js",   //入口文件,即webpack开始打包的入口
        greeter:__dirname+"/js/greeter.js"
    },
    output:{
        path:__dirname+"/build",   //打包出口文件路径
        filename:"[name].js",       //打包后文件名,如果是多入口,引用[name],会将entry的对象中的key作为文件名
        publicPath:"./"
    },
    module:{
        rules:[
            {
                test: /\.(png|jpg)$/,
                use:[
                    {
                        loader:"url-loader",
                        options:{
                            limit:8194,
                            publicPath:"../build"
                        }
                    }
                ]
              },
        ]
    },
    plugins: [
        new webpack.BannerPlugin('大麦所有,盗版必究')
    ]
}

我们添加了plugins属性,该属性的值是一个数组,我们可以在该数组中不断的new 插件的实例对象,通过这样我们就可以改webpack设置插件。

是不是很简单?接着我们打包文件,在终端输入webpack打包。

查看我们的打包后的文件,以bundle.js为例:

bundle.js

/*! 大麦所有,盗版必究 */!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="./",n(n.s=0)}([function(e,t,n){var r=document.createElement("div");r.textContent="Hello Webpack!";var o=document.querySelector("#root");o.appendChild(r);var u=document.createElement("img");u.src=n(1),o.appendChild(u)},function(e,t){e.exports="../build/a2d8df5678e4b3f4b3d686a173544500.jpg"}]);

我们可以看到我们的打包后的文件头部就被添加了文字Banner。

更多的插件,我们可以查看官方的插件文档。这里就不在一一赘述。

复盘

看到这里我们就对webpack有了个最基础的认识,webpack还有很多很丰富的配置,例如热更新,接口代理等,我们今天就学了它的entryoutputmoduleplugins

我是大麦,如果你喜欢我的文章,请给我一颗小心心。