1、什么是Webpack

Webpack一个开源的JavaScript模块打包工具,其最核心功能解决模块之间依赖,把各个模块按照特定的规则顺序组织在一起,最终合并一个JS文件(有时会有多个这里讨论的只是最基本的情况)。这个过程就叫作模块打包

可以把Webpack理解一个模块处理工厂我们源代码交给Webpack,由它去进行加工、拼装处理,产出最终的资源文件等待送往用户

没有接触过打包工具的人可能会疑惑,在Web开发中与我们打交道的无非是HTML、CSS、JS等静态资源为什么直接工程中的源文件发布服务器或CDN,而要交给Webpack处理呢?这两者之间有什么不同接下来我们就来阐述使用Webpack的意义。

2、为什么需要Webpack

开发一个简单的Web应用其实只需要浏览器一个简单编辑器可以了。最早的Web应用就是这么开发的,因为需求简单。当应用的规模大了之后,就必须借助一定的工具,否则人工维护代码成本将逐渐变得难以承受。使用工具可以开发效率成倍地提升,所谓“工欲善其事,必先利其器”就是这个意思。

说回Webpack,既然它解决的最主要问题模块打包,那么为了更好地阐述Webpack的作用我们必须先谈谈模块

2.1、模块

我们每时每刻都在与模块打交道,比如,在工程引入一个日期处理npm包,或者编写一个提供工具方法的JS文件,这些包和文件都可以称为模块。

设计程序结构时,把所有代码都堆到一起是非常糟糕的做法。更好组织方式是按照特定的功能将其拆分为多个代码段每个代码段实现一个特定的目的。你可以对其进行独立设计开发测试,最终通过接口来将它们组合在一起。这就是基本模块化思想。

如果把程序比作一个城市这个城市内部不同的职能部门,如学校、医院、消防局等。程序中的模块就像这些职能部门一样,每一个都有其特定的功能各个模块协同工作,才能保证程序的正常运转。

2.2、JavaScript中的模块

在大多数程序语言(如C、C++、Java)中,开发者可以直接使用模块进行开发工程中的各个模块在经过编译链接过程后会被整合成单一的可执行文件并交由系统运行

对于JavaScript来说,情况则有所不同。在过去的很长一段时间里,JavaScript这门语言没有模块这一概念。如果工程中有多个JS文件,我们只能通过script标签将它们一个个插入页面中。

为何偏偏JavaScript没有模块呢?如果要追溯历史原因,JavaScript之父Brendan Eich最初设计这门语言时只是将它定位成一个小型的脚本语言用来实现网页上一些简单动态特性,远没有考虑到会用它实现今天这样复杂场景模块化当然也就显得多余了。

随着技术发展,JavaScript已经不仅仅用来实现简单的表单提交功能引入多个script文件到页面中逐渐成为一种常态,但我们发现这种做法有很多缺点:

模块化解决上述所有问题

从2009年开始,JavaScript社区开始对模块化进行不断的尝试,并先后给出了AMD、CommonJS、CMD等解决方案。但这些都只是由社区提出的,并不能算作语言本身的特性。而在2015年,ECMAScript 6.0(ES6)正式定义了JavaScript模块标准,使这门语言在诞生了20年之后终于拥有了模块这一概念

ES6模块标准目前已经得到了大多数现代浏览器支持,但在实际应用方面还需要等待一段时间,主要有以下几点原因

那么,如何才能让我们的工程在使用模块化的同时也能正常运行浏览器中呢?这就到了模块打包工具出场的时候了。

2.3、模块打包工具

模块打包工具(module bundler)的任务就是解决模块间的依赖,使其打包后的结果能运行在浏览器上。它的工作方式主要分为两种:

目前社区比较流行的模块打包工具有Webpack、Vite、Parcel、Rollup等。

2.4、为什么选择Webpack

对比同类模块打包工具,Webpack具备以下几点优势:

3、安装Webpack

Webpack对于操作系统没有要求,使用Windows、Mac、Linux操作系统均可。它唯一的依赖就是Node.js,下面来进行安装

Webpack对Node.js版本是有一定要求的,推荐使用Node.js的LTS(Long Term Support,长期维护)版本。LTS版本是Node.js在“当前阶段”较为稳定的版本,具体版本号发布计划可以到https://github.com/nodejs/Release自行查看。LTS版本中不会包含过于激进的特性,并且已经经过了一定时间的检验,比较适合生产环境。大多数Node.js模块也都会依照LTS版本的特性提供支持。

Node.js官网https://nodejs.org/)一般都会把LTS版本放在较为醒目的位置用户根据自己系统环境进行下载安装即可安装完成后,打开命令行执行nodev,不出意外的话会显示当前Node.js版本号代表已经安装成功。

接下来,我们需要使用Node.js的包管理器npm安装Webpack。使用过npm的读者应该知道安装模块的方式有两种:一种是全局安装,一种是本地安装。对于Webpack来说,我们也有这两种选择

全局安装Webpack的好处是npm会帮我们绑定一个命令行环境变量一次安装、处处运行;本地安装Webpack则会添加其为项目中的依赖,只能在项目内部使用。这里建议使用本地安装的方式,主要有以下两点原因

基于以上两点,我们选择在工程内部安装Webpack。首先新建一个工程目录,从命令行进入该目录,并执行npm初始化命令

npm init # 如果你使用 yarn,则为 yarn init

此时会要求你输入项目的基本信息,因为这里只是为了生成一个示例,根据提示操作就好。然后,我们会看到目录中生成了一个package.json文件,它相当于npm项目的说明书,里面记录了项目名称、版本、仓库地址信息

接下来执行安装Webpack的命令

npm install webpack webpack-cli -D
# or yarn
yarn add webpack webpack-cliD

在这里插入图片描述

这里我们同时安装了webpack以及webpack-cliwebpack是核心模块,webpack-cli则是命令行工具,在本例中两者都是必需的。

安装结束之后,在命令行执行npx webpack -v以及npx webpack-cli -v,可显示版本号即证明安装成功。
在这里插入图片描述

注意:由于我们将Webpack安装在了本地,因此无法直接命令行内使用webpack指令。工程内部只能使用npx webpack 的形式,后面会介绍简化命令方法

4、打包第一个应用

现在让我们趁热打铁来打包刚刚的示例工程。如果你是第一次接触Webpack,建议按照下面的指引一步步进行操作。代码中不熟悉的地方也不必深究,这个示例只是为了让我们直观地认识Webpack的一些特性。

4.1、Hello World

首先,我们在工程目录下添加以下几个文件。

index.js

import addContent from './add-content.js';
document.write('My first Webpack app.<br /&gt;');
addContent();

addcontent.js

export default function() {
    document.write('Hello world!');
}

index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>My first Webpack app.</title>
</head>
<body>
    <script src="./main.js"></script>
</body>
</html>

然后控制台输入打包命令

npx webpack --entry=./index.js --mode=development

在这里插入图片描述
Webpack帮我们完成了一项最基本的模块组装工作,现在回顾一下刚刚输入指令

命令行的第1个参数entry是资源打包的入口。Webpack从这里开始进行模块依赖的查找找到index.js和addcontent.js两个模块,并通过它们来生成最终产物。

命令行的第2个参数outputfilename输出资源名。你会发现打包完成后工程中出现了一个dist目录,其中包含main.js就是Webpack的打包结果。

最后参数mode指的是打包模式。Webpack为开发者提供了developmentproductionnone三种模式。当置于developmentproduction模式下时,它会自动添加适合当前模式的一系列配置,减少了人为的工作量。在开发环境下,一般设置development模式就可以了。

为了验证打包结果,可以用浏览打开index.html。项目中的index.js和content.js现在已经成为bundle.js,被页面加载和执行,并输出了各自的内容

4.2、使用npm scripts

从上面的例子不难发现,我们每进行一次打包都要输入一段冗长的命令,这样做不仅耗时,而且容易出错。为了使命令行指令简洁,可以在package.json中添加一脚本命令。

编辑工程中的package.json文件:

……
  "scripts": {
    "build": "webpack --entry=./index.js --mode=development"
  },
……

scripts是npm提供的脚本命令功能,在这里我们可以直接使用由模块添加的指令(比如webpack取代之前的npx webpack)。

为了验证打包结果,可以对addcontent.js的内容稍加修改

export default function() {
    document.write('I'm using npm scripts!');
}

重新打包,这次输入npm命令即可

npm run build

打开浏览验证效果,如下图所示
在这里插入图片描述

4.3、使用默认目录配置

上面的index.js是放在工程根目录下的,而通常情况下我们会分别设置源码目录与资源输出目录。工程源代码放在/src中,输出资源放在/dist中。本贴后续的示例也会按照该标准进行目录划分

在工程中创建一个src目录,并将index.js和addcontent.js移动到该目录下。对于资源输出目录来说,Webpack已经默认是/dist,我们不需要做任何改动。

另外需要提到的是,Webpack默认源代码入口就是src/index.js,因此现在可以省略entry配置了。编辑package.json

……
  "scripts": {
    "build": "webpack --output-filename=bundle.js --mode=development"
  },
……

虽然目录命名并不是强制的,且Webpack提供了配置项让我们进行更改,但还是建议遵循统一命名规范,这样会使得大体结构比较清晰,也利于多人协作

4.4、使用配置文件

为了满足不同应用场景需求,Webpack拥有非常多的配置项以及相对应的命令行参数。我们可以通过Webpack的帮助命令来进行查看

npx webpack –h

部分参数下图所示
在这里插入图片描述
从之前我们在package.json添加脚本命令来看,当项目需要越来越多的配置时,就要往命令中添加更多的参数,那么到后期维护起来就会相当困难。为了解决这个问题,可以把这些参数改为对象的形式专门放在一个配置文件里,在Webpack每次打包的时候读取该配置文件即可

Webpack的默认配置文件为webpack.config.js(也可以使用其他文件名,需要使用命令行参数指定)。现在让我们在工程根目录创建webpack.config.js,并添加如下代码:

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'main.js',
    },
    mode: 'development',
}

上面通过module.exports导出了一个对象,也就是打包时被Webpack接收的配置对象。先前在命令行中输入的一大串参数就都要改为keyvalue的形式放在这个对象中。

目前该对象包含两个关于资源输入输出属性——entryoutputentry就是我们的资源入口,output则是一个包含更多详细配置的对象。在Webpack配置中,我们经常会遇到这种层叠的属性关系。这是由于Webpack本身的配置实在太多,如果都放在同一级会难以管理,因此出现了这种多级配置。当开发者修改某个配置项时,通过层级关系找下来会更加清晰、快捷。

之前的参数–outputfilename和–outputpath现在都成为output下面的属性。filename和先前一样都是bundle.js,不需要改动,而path和之前有所区别。Webpack对于output.path的要求是使用绝对路径(从系统根目录开始的完整路径),之前我们在命令行中为了简洁而使用了相对路径。而在webpack.config.js中,我们通过调用Node.js的路径拼装函数path.join,将__dirname(Node.js内置全局变量值为当前文件所在的绝对路径)与dist(输出目录)连接起来,得到了最终的资源输出路径。

现在我们可以去掉package.json中配置的打包参数了:

……
  "scripts": {
    "build": "webpack"
  },
……

为了验证最终效果,我们再对add-content.js的内容稍加修改:

export default function() {
    document.write('I'm using a config file!');
}

执行npm run build命令,Webpack就会预先读取webpack.config.js,然后打包。完成之后我们打开index.html进行验证,结果如下图所示
在这里插入图片描述

4.5、webpack-devserver

这里,其实我们已经把Webpack的初始环境配置好了。你可能发现,单纯使用Webpack以及它的命令行工具来进行开发调试效率并不高。以往只要编辑项目源文件(JS、CSS、HTML等),刷新页面即可看到效果,现在多了一步打包,即我们在改完项目源码后要执行npm run build更新bundle.js,然后才能刷新页面生效。有没有更简便的方法呢?

其实Webpack社区已经为我们提供了一个便捷的本地开发工具——webpack-dev-server。用以下命令进行安装:

npm install webpack-dev-server -D

安装指令中的-D参数是将webpack-dev-server作为工程的devDependencies开发环境依赖)记录在package.json中。这样做是因为webpack-dev-server仅仅在本地开发时才会用到,在生产环境中并不需要它,所以放在devDependencies中是比较恰当的。假如工程上线时要进行依赖安装,就可以通过npm installonly=prod过滤掉devDependencies中的冗余模块,从而加快安装和发布速度

为了便捷地启动webpack-dev-server,我们在package.json中添加一个dev指令:

……
  "scripts": {
    "build": "webpack",
    "dev": "webpack-dev-server"
  },
……

最后,我们还需要对webpack-dev-server进行配置。编辑webpack.config.js:

module.exports = {
    entry: './src/index.js',
    output: {
        filename: './main.js',
    },
    mode: 'develpoment',
    devServer: {
        publicPath: '/dist',
    },
};

可以看到,我们在配置中添加了一个devServer对象,它是专门用来放webpack-dev-server配置的。webpack-dev-server可以看作一个服务者,它的主要工作就是接收浏览器的请求然后将资源返回。当服务启动时,它会先让Webpack进行模块打包并将资源准备好(在示例中就是bundle.js)。当webpack-dev-server接收浏览器的资源请求时,它会首先进行URL地址校验。如果该地址是资源服务地址(上面配置的publicPath),webpack-dev-server就会从Webpack的打包结果中寻找该资源并返回浏览器。反之,如果请求地址属于资源服务地址,则直接读取硬盘中的源文件并将其返回

综上我们可以总结出webpack-dev-server的两大职能:

  • 令Webpack进行模块打包,并处理打包结果的资源请求。
  • 作为普通的Web Server,处理静态源文件请求。

最后,在启动服务之前,我们还是更改一下add-content.js:

export default function() {
    document.write('I'm using webpack-dev-server!');
}

一切就绪执行 npm run dev命令并用浏览打开http://localhost:8080/,可以看到下图所示的输出结果:
在这里插入图片描述
这里有一点需要注意。直接用Webpack开发和使用webpack-dev-server有一个很大的区别,前者每次都会生成main.js,而webpack-dev-server只是将打包结果放在内存中,并不会写入实际的bundle.js,在每次webpack-dev-server接收到请求时都只是将内存中的打包结果返回浏览器。

这一点可以通过删除工程中的dist目录来验证,你会发现即便dist目录不存在,刷新页面后功能仍然是正常的。从开发者角度来看,这其实是符合情理的。在本地开发阶段我们经常会调整目录结构和文件名,如果每次都写入实际文件,最后就会产生一些没用的垃圾文件,还会干扰我们的版本控制,因此webpack-dev-server的处理方式显得更加简洁。

webpack-dev-server还有一项很便捷的特性——livereloading自动刷新)。例如我们保持本地服务启动以及浏览打开状态,到编辑器中去更改add-content.js:

export default function() {
    document.write('This is from live-reloading!');
}

此时切回到浏览器,你会发现浏览器的内容自动更新了,这就是livereloading功能。当webpack-dev-server发现工程源文件进行了更新操作后就会自动刷新浏览器,显示更新后的内容。该特性可以提升本地开发的效率。在后面我们还会讲到更先进的hot-modulereplacement(模块热替换),甚至不需要刷新浏览器就能获取更新之后的内容。

原文地址:https://blog.csdn.net/YYBDESHIJIE/article/details/134651767

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_40502.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注