webpack基本功能学习总结

版权声明:本文为神州灵云作者的原创文章,未经神州灵云允许不得转载。

本文作者:Spike

前言

笔者开发的项目,是通过脚手架工具搭建的,默认就配置了Webpack,而且配置文件还分成很多个文件。打开文件一看,里面有很多配置,如entry,loader,plugins…粗一看有些云里雾里,阅读了官网文档以及一些文章后,对一些基本概念了解了些,在此对webpack的学习做一下总结。

什么是Webpack

Webpack是一个打包器,它能够把我们写的代码,经过一些处理,如压缩,转译(babel)等,打包成我们用于最终发布的代码。

Webpack有什么作用

模块化

Webpack默认支持js文件的模块化,除此之外,借助loader也能对其他资源如css,font,icon等资源进行模块化处理。
(模块化,允许我们把各种资源分成若干文件,在文件中把资源导出,用到的地方把资源导入。这样便于我们去组织代码结构。)

压缩

Webpack可以把源码进行压缩,去除一些无用代码,使得打包后的代码体积更小便于发布,浏览器加载起来也会更快。

代码转译

Webpack通过借助一些loader,如babel-laoder,可以对源码进行转译。使得我们可以用较新的语法,如ES6,ES7等去编写代码,而不需要担心浏览器是否支持,它能帮我们转译成浏览器支持的语法。

提供许多便捷的功能

Webpack还提一些对开发者很有用的功能,如模块热替换(HMR),可以让我们改动代码后,立即再页面看到修改后的变化,且不需要刷新页面。

基本概念介绍

基本安装

  • 前提: 确保安装了Node.js的最新版本
  • 创建一个目录
mkdir webpack-demo cd webpack-demo 
  • 初始化npm
npm init -y 
  • 安装webpack和webpack-cli(用于再命令行中运行webpack)
npm install --save-dev webpack webpack-cli 

安装完成后,目录结构应该是这样的:

  webpack-demo
  |- node_modules
  |- package.json
  |- package-lock.json

基本功能

首先,考虑一下在不用webpack时的写法。假设需要用到lodash这个库。

我们先添加两个文件index.htmlindex.js:

project

  webpack-demo
  |- node_modules
  |- package.json
  |- package-lock.json
+ |- index.html
+ |- index.js

index.html

<!doctype html> <html> <head> <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script> </head> <body> <div id="div"></div> <script src="./index.js"></script> </head> </body> </html> 

index.js

const divElement = document.getElementById('div'); // 引用lodash库拼接字符串,lodash通过页面的script标签引入 divElement.innerHTML = _.join(['hello', 'world'], ' '); 

可以看到,在这个例子中index.js中依赖了lodash库(’_’),而lodash库是在index.html文件中通过script标签引入的。这种依赖关系有几个问题:

  • 这种依赖关系是隐性的,光是看index.js这个文件,我们并不知道是否引入了外部的库。
  • 如果script标签里引入的库缺失了, 就会导致依赖这个库的代码无法运行(例如引用的cdn挂了)。
  • 如果script标签中引入的库没有被依赖,但是它还是会被浏览器下载下来,减慢了页面的加载速度。

而通过Webpack模块化代码,我们就可以规避以上的问题。

为此,我们需要对项目结构以及文件内容做些调整。

project

  webpack-demo
  |- node_modules
  |- package.json
  |- package-lock.json
- |- index.html
- |- index.js
+ |- /dist
+   |- index.html
+ |- /src
+   |- index.js
  • 创建一个dist目录,把index.html移到这个目录下
  • 创建一个src目录,把index.js移动到这个目录下

为什么要这么做呢,因为在没有任何Webpack配置的情况下,Webpack打包的默认入口(entry)是/src/index.js. 而默认输出(output)则是/dist/main.js

接着,为了以模块化的方式引入lodash,我们需要在项目中安装lodash这个库.

npm install --save lodash 

安装成功后,package.json这个文件中,应该会增加一个lodash的依赖。

package.json

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  },
+  "dependencies": {
+    "lodash": "^4.17.11"
+  }
}

安装好lodash后,我们调整一下src/index.js,显式地引入lodash模块:

src/index.js

+ import _ from 'lodash';

const divElement = document.getElementById('div');
- // 引用lodash库拼接字符串,lodash通过页面的script标签引入
+ // 现在我们通过从本地的库中,把lodash引入进来。
+ // 这样,lodash的依赖就是显式的,我们能清楚地知道,index.js需要依赖lodash
divElement.innerHTML = _.join(['hello', 'world'], '  ');

调整一下dist/index.html, 去掉script标签引入的lodash,引用webpack打包后的文件,即main.js:

dist/index.html

<!doctype html>
<html>
  <head>
-    <script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
  </head>
  <body>
    <div id="div"></div>
-    <script src="./index.js"></script>
+    <script src="./main.js"></script>
  </head>
  </body>
</html>

文件都调整好之后,我们就需要用Webpack进行打包,Webpack会从入口文件开始(src/index.js)找到所有的依赖,如lodash,然后把他们打包到一个或多个文件中,本例中,就是打包到dist/main.js.

npx webpack

npx 指令,可以执行我们指定的库的脚本。npx webpack 就是去执行webpack的脚本,你可以在node_modules/.bin/ 目录下找到webpack的脚本。感兴趣的话,可以看看npx文档

$ npx webpack npx: installed 1 in 7.471s Path must be a string. Received undefined E:\github\webpack-demo\node_modules\webpack\bin\webpack.js Hash: 61f045951826de0b0c9e Version: webpack 4.29.0 Time: 409ms Built at: 2019-02-03 10:22:32 Asset Size Chunks Chunk Names main.js 70.3 KiB 0 [emitted] main Entrypoint main = main.js [1] ./src/index.js 172 bytes {0} [built] [2] (webpack)/buildin/global.js 472 bytes {0} [built] [3] (webpack)/buildin/module.js 497 bytes {0} [built] + 1 hidden module WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/ 

打包顺利的话,你应该能看到类似的输出,可以看到,最终打包生成了一个main.js的文件。这个时候,再次打开dist/index.html,如果运行正常,你应该能看到hello world的文本。

如果你觉得npx webpack使用起来不方便,那么可以在package.json里加入一些脚本(script),使用一些便于记忆的别名来执行打包操作。

package.json

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
+    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
  },
  "dependencies": {
    "lodash": "^4.17.11"
  }
}

我们可以在package.jsonscript属性下,添加一些脚本,例如添加一个叫build的脚本,它的值为webpack.

可以通过npm run去执行它。于是就可以这样去执行webpack的打包.

$ npm run build > [email protected] build E:\github\webpack-demo > webpack Hash: 61f045951826de0b0c9e Version: webpack 4.29.0 Time: 498ms Built at: 2019-02-04 21:30:40 Asset Size Chunks Chunk Names main.js 70.3 KiB 0 [emitted] main Entrypoint main = main.js [1] ./src/index.js 172 bytes {0} [built] [2] (webpack)/buildin/global.js 472 bytes {0} [built] [3] (webpack)/buildin/module.js 497 bytes {0} [built] + 1 hidden module WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/ 

以上,我们只是对javascript进行了模块化处理,但是前端项目中,往往还有很多别的东西,例如图片,字体,css等,那么这些资源是否也能模块化呢?如果可以,这些资源也能拥有模块化的优点,如显示依赖等。

如果你按照文章写的做下来,那么现在打开dist/index.html你会看到黑色的hello world的文本,接下来,我们添加一些css,使得文字颜色变成红色。

如果按照不用webpack前的做法,是这样的:

首先,在src目录下,添加一个style.css文件,用于写样式。

project

  webpack-demo
  |- node_modules
  |- package.json
  |- package-lock.json
  |- /dist
    |- index.html
  |- /src
    |- index.js
+   |- style.css

src/style.css

+ .red {
+   color: red;
+ }

为了能够用style.css的样式,首先我们得把它引入进来。

dist/index.html

<!doctype html>
<html>
  <head>
+ <link href="../src/style.css" rel="stylesheet" type="text/css">
  </head>
  <body>
    <div id="div"></div>
    <script src="./main.js"></script>
  </head>
  </body>
</html>

给元素加上我们定义的类名:

src/index.js

import _ from 'lodash';

const divElement = document.getElementById('div');
// 现在我们通过从本地的库中,把lodash引入进来。
// 这样,lodash的依赖就是显式的,我们能清楚地知道,index.js需要依赖lodash
divElement.innerHTML = _.join(['hello', 'world'], '  ');
+ divElement.classList.add('red');

然后我们需要更新一下dist/main.js, 执行npm run build重新打包一下就好了。

一切顺利的话,再打开dist/index.html,你应该能看到红色的hello world文本。

不过我们是直接从index.html中通过link标签引入的, 还是存在隐式引入造成的问题:

  • 这种依赖关系是隐性的,光是看index.js这个文件,我们并不知道是否引入了外部的css文件。
  • 如果没有被依赖,style.css还是会被浏览器下载下来,减慢了页面的加载速度。

那么是否可以像引入lodash库一般,通过import语句,显示的引入呢?

首先,去掉在index.html的引入:

dist/index.html

<!doctype html>
<html>
  <head>
- <link href="../src/style.css" rel="stylesheet" type="text/css">
  </head>
  <body>
    <div id="div"></div>
    <script src="./main.js"></script>
  </head>
  </body>
</html>

然后,在src/index.js中,将src/style.css引入进来。

import _ from 'lodash';
+ import './style.css';

const divElement = document.getElementById('div');
// 现在我们通过从本地的库中,把lodash引入进来。
// 这样,lodash的依赖就是显式的,我们能清楚地知道,index.js需要依赖lodash
divElement.innerHTML = _.join(['hello', 'world'], '  ');
divElement.classList.add('red');

最后,执行npm run build打包生成最新代码:

$ npm run build > [email protected] build E:\github\webpack-demo > webpack Hash: 2b107bfc2e7dc8009bf8 Version: webpack 4.29.0 Time: 410ms Built at: 2019-02-05 09:03:10 1 asset Entrypoint main = main.js [0] ./src/index.js 242 bytes {0} [built] [failed] [1 error] WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/ ERROR in ./src/index.js 2:9 Module parse failed: Unexpected token (2:9) You may need an appropriate loader to handle this file type. | import _ from 'lodash'; > import * from './style.css'; | | const divElement = document.getElementById('div'); ... 

我们发现,打包失败了,出现了一个错误:

You may need an appropriate loader to handle this file type.

错误提示,我们需要一个叫loader的东西去处理.css这种文件类型。

可以看看,官网文档对于loader的定义:

loader 用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!

也就是说,loader可以让我们对各种类型的文件进行预处理,做一些转换,转译等,得到我们需要的东西。

那么,我们尝试用loader去处理一下css文件.

首先,我们需要安装用于处理cssloader. 这个网站上有一些常用的loader, 对于上面例子的css文件,需要用到style-loader, css-loader.

npm install --save-dev style-loader css-loader 

package.json

{
  "name": "webpack-demo",
  "version": "1.0.0",
  ...
  "devDependencies": {
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
+   "css-loader": "^2.1.0",
+   "style-loader": "^0.23.1",
  },
  ...
}

接着,我们需要配置webpack去使用这些loader去处理css文件.为此,需要创建一个配置文件。webpack默认会读取根目录下的webpack.config.js文件作为配置文件

project

  webpack-demo
  |- node_modules
  |- package.json
  |- package-lock.json
+ |- webpack.config.js
  |- /dist
    |- index.html
  |- /src
    |- index.js
    |- style.css

webpack.config.js

// 引入path模块,处理路径 const path = require('path'); module.exports = { // webpack打包的入口,从这个入口开始查找所有依赖 // 默认是`./src/index.js` entry: './src/index.js', // 打包完成后,输出的目录 // 默认是`./dist/main.js` output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') }, // loader相关的写在`module`这个配置中 module: { // `rules`是一个数组,可以对不同文件,应用不同的loader rules: [ { // `test`用于匹配文件 test: /\.css$/, // `use`表示使用什么`loader` use: [ 'style-loader', 'css-loader' ] } ] } }; 

上面配置中,入口(entry)用于配置webpack打包的入口,webpack会从这个入口开始,查找所有的依赖模块。

输出(output)则配置webpack打包后的输出.指定了打包后的文件放于什么地方,要输出成什么样子等。

loader则是通过module.rules这个属性进行配置。rules是一个数组,可以包含多个规则,针对不同的文件应用不同的loader. 现在我们需要去预处理css文件,可以在rules中添加一个配置

{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } 

test: /\.css$/ 匹配了所有以.css为后缀的文件

use: ...表示要用什么loader去处理匹配的文件

所以这个配置的意思就是用style-loadercss-loader去处理.css后缀的文件。

此时,再次执行一下webpack的打包脚本:

$ npm run build > [email protected] build E:\github\webpack-demo > webpack Hash: f5f42a15b1b3287f060d Version: webpack 4.29.0 Time: 1747ms Built at: 2019-02-07 23:07:42 Asset Size Chunks Chunk Names main.js 76.2 KiB 0 [emitted] main Entrypoint main = main.js [1] ./src/index.js 266 bytes {0} [built] [2] (webpack)/buildin/global.js 472 bytes {0} [built] [3] (webpack)/buildin/module.js 497 bytes {0} [built] [4] ./src/style.css 1.06 KiB {0} [built] [5] ./node_modules/css-loader/dist/cjs.js!./src/style.css 166 bytes {0} [built] + 4 hidden modules WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/ 

加了loader去处理css文件后,这次打包就没有出现错误了。打开dist/index.html就能看到红色的hello world文本了。

类似地,我们也可以用loader去处理图片,字体等,这样我们就可以显式地引入各种各样的文件。此外,loader也可以转译,例如把Typescript转为Javascript,把ES6语法写的代码转为ES5的语法等。

例如,我们可以添加一个babel loader去转译用ES6语法写的代码.

首先,我们用ES6的语法写点东西:

src/index.js

import _ from 'lodash';
import './style.css';

const divElement = document.getElementById('div');
// 现在我们通过从本地的库中,把lodash引入进来。
// 这样,lodash的依赖就是显式的,我们能清楚地知道,index.js需要依赖lodash
divElement.innerHTML = _.join(['hello', 'world'], '  ');
divElement.classList.add('red');

+ // 使用ES6的箭头函数
+ [1, 2, 3].forEach(n => console.log(n));

在没有用babel loader之前,我们先打包看看是怎样的。

babel处理前

如上图,可以看到打包到main.js的代码,和我们写的基本上是一模一样的,也是ES6的语法。但是有的浏览器可能还不支持ES6的语法,就可能导致报错,为了解决这种问题,就可以用babel去转译。

按照官网关于babel安装教程,我们把babel安装并配置好。

安装babel相关依赖:

npm install [email protected] @babel/core @babel/preset-env webpack 

package.json

{
  "name": "webpack-demo",
  "version": "1.0.0",
  ...
  "devDependencies": {
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1"
    "css-loader": "^2.1.0",
    "style-loader": "^0.23.1",
+   "@babel/core": "^7.2.2",
+   "@babel/preset-env": "^7.3.1",
+   "babel-loader": "^8.0.5",
  },
  ...
}

在webpack中配置babel loader:

webpack.config.js

// 引入path模块,处理路径
const path = require('path');

module.exports = {
  // webpack打包的入口,从这个入口开始查找所有依赖
  // 默认是`./src/index.js`
  entry: './src/index.js',
  // 打包完成后,输出的目录
  // 默认是`./dist/main.js`
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  // loader相关的写在`module`这个配置中
  module: {
    // `rules`是一个数组,可以对不同文件,应用不同的loader
    rules: [
      {
        // `test`用于匹配文件
        test: /\.css$/,
        // `use`表示使用什么`loader`
        use: [
          'style-loader',
          'css-loader'
        ]
      },
+     {
+       test: /\.js$/,
+       // 排除node_modules 和 bower_components下的文件
+       exclude: /(node_modules | bower_components)/,
+       use: {
+         loader: 'babel-loader',
+         options: {
+           presets: ['@babel/preset-env'],
+         },
+       },
+     },
    ]
  }
};

再次执行打包命令, 再看看打包后的main.js:
babel处理后
可以看到,原来的箭头函数,被转译成普通的函数,这样就算浏览器不支持ES6的语法,运行起来也不会出问题。

但是,问题又来了,这段ES6语法的代码,是写在src/index.js中的,可是我们调试的时候,却只能进到main.js中查看,而且main.js中可能包含很多其他的代码,不便于我们调试。是否可以让我们调试的时候,能看到原始的代码?答案是肯定的,我们需要启用webpack的source map.

source map是压缩后的代码与源码之间的映射,主要是便于我们调试时,去定位代码。source map通过webpack配置中的devtool选项进行配置。可选配置有很多,在这里我们使用inline-cheap-source-map.

webpack.config.js

// 引入path模块,处理路径
const path = require('path');

module.exports = {
  // webpack打包的入口,从这个入口开始查找所有依赖
  // 默认是`./src/index.js`
  entry: './src/index.js',
  // 打包完成后,输出的目录
  // 默认是`./dist/main.js`
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  },
  // loader相关的写在`module`这个配置中
  module: {
    ...
  },
+ devtool: 'inline-source-map',
};

再次执行打包,然后打开浏览器控制台,我们就能看到源码所在的文件及行号:
devtool

看到这里,你应该了解了:

  • 怎么使用webapck进行打包 (npx webpack, npm run build)
  • 怎么处理各种类型的文件,可以显式地引入它们 (使用loader)
  • 怎么转译源码 (使用loader)
  • 怎么可以在打包后,方便地定位源码 (使用source map, devtool)

到这里,我们回头看看当前的webpack配置文件:

webpack.config.js

// 引入path模块,处理路径 const path = require('path'); module.exports = { // webpack打包的入口,从这个入口开始查找所有依赖 // 默认是`./src/index.js` entry: './src/index.js', // 打包完成后,输出的目录 // 默认是`./dist/main.js` output: { filename: 'main.js', path: path.resolve(__dirname, 'dist') }, // loader相关的写在`module`这个配置中 module: { // `rules`是一个数组,可以对不同文件,应用不同的loader rules: [ { // `test`用于匹配文件 test: /\.css$/, // `use`表示使用什么`loader` use: [ 'style-loader', 'css-loader' ] }, {, test: /\.js$/, // 排除node_modules 和 bower_components下的文件 exclude: /(node_modules | bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'], }, }, }, ] } }; 

你会发现,我们把所有打包后的代码,都输出到main.js这个文件里。

随着代码的增多,main.js会越来越大,浏览器要去下载一个这么大的文件,就需要花不少时间。

因此,我们最好把代码拆开一些,使得打包后的每个文件大小都不那么大,浏览器去请求加载时,就会快一些。

最简单的拆分方法,就是拆分入口。

首先,调整一下目录结构,新增一个模块print.js:

project

  webpack-demo
  |- node_modules
  |- package.json
  |- package-lock.json
  |- /dist
    |- index.html
  |- /src
    |- index.js
    |- style.css
+   |- print.js

src/print.js

export default function print() { console.log('hello, i am from print.js'); } 

src/index.js

import _ from 'lodash';
import './style.css';
+ import print from './print.js';

const divElement = document.getElementById('div');
// 现在我们通过从本地的库中,把lodash引入进来。
// 这样,lodash的依赖就是显式的,我们能清楚地知道,index.js需要依赖lodash
divElement.innerHTML = _.join(['hello', 'world'], '  ');
divElement.classList.add('red');

// 使用ES6的箭头函数
[1, 2, 3].forEach(n => console.log(n));

+ print();

配置一下webpack, 使入口分开,还要调整一下输出:

webpack.config.js

// 引入path模块,处理路径
const path = require('path');

module.exports = {
  // webpack打包的入口,从这个入口开始查找所有依赖
- // 默认是`./src/index.js`
- entry: './src/index.js',
+ entry: {
+   app: './src/index.js',
+   print: './src/print.js',
+ },
  // 打包完成后,输出的目录
-  // 默认是`./dist/main.js`
  output: {
-   filename: 'main.js',
+   // 为了保证打包后的文件名不重复,根据入口名称生成文件名
+   filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  },

  // loader相关的写在`module`这个配置中
  module: {
   ...
  }
};

按照这份配置,最终会打包出来两个文件,分别是app.jsprint.js;

还需要改一下index.html文件,引入打包后的文件:

index.html

<!doctype html>
<html>
  <head>
+   <script src="./print.js"></script>
  </head>
  <body>
    <div id="div"></div>
-    <script src="./main.js"></script>
+    <script src="./app.js"></script>
  </head>
  </body>
</html>

一切准备就绪,执行一下打包命令:

$ npm run build > [email protected] build E:\work\document\webpack-demo > > webpack > > [BABEL] Note: The code generator has deoptimised the styling of E:\work\document\webpack-demo\node_modules\lodash\lodash.js as it exceeds the max of 500KB. > Hash: 8c6bb8021477ab0ea39b > Version: webpack 4.29.3 > Time: 1928ms > Built at: 2019-02-12 23:36:59 > Asset Size Chunks Chunk Names > app.js 77.1 KiB 0, 1 [emitted] app > print.js 1.03 KiB 1 [emitted] print > Entrypoint app = app.js > Entrypoint print = print.js > [0] ./src/print.js 170 bytes {0} {1} [built] > [1] (webpack)/buildin/amd-options.js 80 bytes {0} [built] > [2] ./src/index.js 587 bytes {0} [built] > [4] (webpack)/buildin/global.js 893 bytes {0} [built] > [5] (webpack)/buildin/module.js 567 bytes {0} [built] > [6] ./src/style.css 1.06 KiB {0} [built] > [7] ./node_modules/css-lojkkkkjjkader/dist/cjs.js!./src/style.css 165 bytes {0} [built] > + 4 hidden modules 

可以看到,和预期一样,打包出来了两个文件,顺利地拆分了代码.

尽管我们将代码分离了,但上面步骤还存在一些问题,假设最终打包出来的文件很多,
我们要将打包生成的文件一一引入index.html,如果其中一个文件名字变化了,我们也要相应的对index.html进行修改。
这么做,一方面很麻烦,另外也比较容易出错。

所幸,有人考虑到这样的问题,做了个webpack插件,html-webpack-plugin,
这个插件会生成一个新的index.html,把打包后的所有依赖文件都注入,替换掉旧的index.html文件。这样就不需要手动去改index.html了。

loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务,插件的范围包括:打包优化、资源管理和注入环境变量。

插件目的在于解决 loader 无法实现的其他事。

使用插件很简单,你只要安装插件,然后在webpack配置的plugins部分去配置一下这个插件,就可以了。

使用html-webpack-plugin插件,首先要安装它:

npm install --save-dev html-webpack-plugin

然后再webpack.config.js文件里,配置一下这个插件:

// 引入path模块,处理路径
const path = require('path');
+ // 引入插件模块
+ const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // webpack打包的入口,从这个入口开始查找所有依赖
  entry: {
    app: './src/index.js',
    print: './src/print.js',
  },
  // 打包完成后,输出的目录
  output: {
  // 为了保证打包后的文件名不重复,根据入口名称生成文件名
  filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  },

  // loader相关的写在`module`这个配置中
  module: {
   ...
  },
+ // 在plugins部分配置各种插件
+ plugins: [
+   // 生成一个插件实例,根据插件的文档,你还可以传入别的配置
+   new HtmlWebpackPlugin(),
+ ],
};

配置完后,执行一下打包操作:

$ npm run build > [email protected] build E:\work\document\webpack-demo > webpack [BABEL] Note: The code generator has deoptimised the styling of E:\work\document\webpack-demo\node_modules\lodash\lodash.js as it exceeds the max of 500KB. Hash: 09c786d0341ff909369e Version: webpack 4.29.3 Time: 1892ms Built at: 2019-02-13 00:09:09 Asset Size Chunks Chunk Names app.js 77.1 KiB 0, 1 [emitted] app index.html 234 bytes [emitted] print.js 1.03 KiB 1 [emitted] print Entrypoint app = app.js Entrypoint print = print.js [0] ./src/print.js 170 bytes {0} {1} [built] [1] (webpack)/buildin/amd-options.js 80 bytes {0} [built] [2] ./src/index.js 587 bytes {0} [built] [4] (webpack)/buildin/global.js 893 bytes {0} [built] [5] (webpack)/buildin/module.js 567 bytes {0} [built] [6] ./src/style.css 1.06 KiB {0} [built] [7] ./node_modules/css-loader/dist/cjs.js!./src/style.css 165 bytes {0} [built] + 4 hidden modules ... Child html-webpack-plugin for "index.html": 1 asset Entrypoint undefined = index.html [2] (webpack)/buildin/global.js 893 bytes {0} [built] [3] (webpack)/buildin/module.js 567 bytes {0} [built] + 2 hidden modules 

这个时候,你再去看看dist/index.html文件,你会发现已经变成一个新文件,并且打包生成的文件也都自动引入进去了。

webpack为提供了很多插件,可以实现各种功能,你甚至还可以自己写一个插件.

到这为止,就是笔者认为的webpack的基本功能了。而webpack的配置,基本就是以下几个部分:

  • entry 配置入口,根据这个入口查找所有依赖
  • output 配置输出,怎么输出,输出到哪里…
  • loader 处理各种类型的文件,使其可以模块化地使用; 可以转译源码; 封装了模块热加载的一些处理逻辑…
  • plugins 一些扩展插件,可以实现各种功能

除了这些基本功能外,webpack还提供了很多有用的功能:

  • 模块热加载
  • tree shaking
  • shimming
  • source map配置
  • 缓存
  • 懒加载
  • 性能优化

对于webpack的配置和功能有个整体了解了,具体遇到问题,根据不同的配置模块,看看官网文档应该就能解决了吧。

参考文档

神州灵云公司官网(二维码).png

猜你喜欢

转载自blog.csdn.net/dclingcloud/article/details/87203289
今日推荐