想要学习Webpack前端工程化构建,你必需要掌握这些核心知识点

引言

在好久以前,模块化管理尚未出现,若是咱们开发一个页面想要引入一些依赖的话,最多见的作法就是将依赖文件引入到.html文件中。好比,咱们要使用JS的一些依赖库,就要在.html文件中使用<script>标签引用;要引用CSS的依赖就要使用<link>标签。若是页面中引入的依赖文件太多,那么向服务发送的请求也随之增多,势必会拖慢网页的加载速度,影响用户体验。另外,网页的内容也会变得很臃肿,增长维护的难度。javascript

在移动互联网时代的网站,正在逐渐演化成Web应用(Web Application,简称WebAPP),浏览器也在此之际不断的发展壮大,各类基于JavaScript语言的框架横空出世,Web前端发展速度着实之快,让咱们也不得不加快学习的脚步。如今的Web前端更倾向于单页面应用(single-page application,简称SPA),减小页面的刷新次数,这就形成了庞大的页面代码管理问题,若是管理很差会致使不少问题,好比各个模块耦合度变高、难以维护等等。这就催生了模块管理器。css

简单来讲,Webpack就是一个“模块打包机”,它的主要工做就是分析项目中的结构找到JavaScript模块,根据各个模块之间的依赖关系进行静态分析,而后打包成一个独立的静态模块供浏览器调用,这样就能够大大减小请求次数,提供网页的性能,提升用户的体验。Webpack还有一个做用就是把浏览器目前还解释不了的扩展语言(例如ScssTypeScript等)进行编译,转换成浏览器能够识别的内容。React中使用的是ES6的语法,在一些主流的浏览器上还不支持ES6,全部须要对Webpack进行配置后,React才能正常运行。html

Webpack不只是学习前端框架的前提,也是同窗们未来面试必问、笔试必考、工做必用的内容,随着前端工程化的发展,Webpack正在变得愈来愈重要,尤为对于大型的一线互联网公司,会不会Webpack甚至能直接决定你是否能被录用。我从一个技术小白到全栈工程师,也经历了前端开发从刀耕火种到百家争鸣的各个阶段,在这个过程当中沉淀了不少知识,也积累了大量的实践经验,也但愿经过个人知识分享,让更多同窗受益,避免你们踩坑。前端

一、Webpack简介与环境搭建

如今的网页开发愈来愈复杂,咱们能够把网页看作是一个功能丰富的应用,为了实现复杂的功能,就须要导入不少的JavaScript库和一大堆依赖包。为了简化开发的复杂度,前端社区也涌现出了不少的方法,以便于提升开发效率。可是利用一些方法开发的文件每每须要进行额外的处理才能让浏览器识别,并且手动处理又很是的繁琐,这就为Webpack这样的工具诞生提供了需求。java

1.一、模块化与工程化

随着Web前端的不断发展,前端开发也正在逐渐往Web应用的方式转变,应用场景也变的愈来愈复杂,须要更新的技术来解决开发中遇到的问题。前端模块化和工程化也呼之欲出,前些年比较流行的构建工具备GruntGulpFIS等,可是通过近几年ReactVue框架的发展,不在使用传统的方式来操做DOM。在这个过程当中,前端逐渐发展成了模块化和单页应用为主的形式。node

Webpack也就是在这样的发展潮流中,被更多的人视为主流的前端构建工具。这也就引出了咱们如今要讲的模块化和工程化。react

百度百科是这样解释模块化的:webpack

模块化是指解决一个复杂问题时,自顶向下逐层把系统划分红若干模块的过程,有多种属性、分别反映其内部特性。git

在咱们的生活中也常常会见到模块化的应用场景,好比如今的家用电器(电视机、电脑主机等)都是模块化的,若是这些家电坏了,维修的时候通常都是直接拿个新的模块更换一下就能够了,由此能够看出,模块化不只仅是编程语言的概念。模块化应用到生活中,一样是能够提升办事效率的。github

那咱们主要说的前端模块化具体指什么呢?

前端模块化通常指的是JavaScript的模块,最多见的是Node.js中的NPM包管理,有了模块化,咱们在写代码的时候就避免了不少的重复工做,也不在只是作copy的事情了。有了模块化以后,开发者能够把更多的时间精力放到业务逻辑和代码的维护上。目前,有不少主流的模块化规范,好比CommonJSAMDES6 Module等规范,甚至在CSS中也采用了@import的方式实现模块化。LessSass做为CSS的预处理语言,使用了@import来导入一些变量、函数和mixin的定义。

接下来,咱们在聊聊什么是工程化。当开发Web应用的场景愈来愈复杂时,咱们所面临的问题也会随之增长:

  1. 在大型项目中,多模块下如何管理依赖?

  2. 页面复杂度提高以后,多页面、多系统、多状态怎么办?

  3. 团队协做开发中如何统一规范?

    ……

以上这些问题都是在软件工程中必需要解决的问题,工程化问题须要运用工程化工具来解决。在早期,前端工程化主要是以GruntGulp等构建工具为主,在这个时期解决的是重复任务的问题,他们将某些功能拆解成固定步骤的任务,而后编写工具来解决,好比:图片压缩、地址添加hash等,都是固定套路的重复工做。

在近几年,前端工程化的发展得益与Node.js的发展,Webpack的插件机制解决了前端资源依赖管理的问题,从而进化成了一整套前端工程化解决方案。

1.二、什么是Webpack

官方解释:

本质上,webpack 是一个现代JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序须要的每一个模块,而后将全部这些模块打包成一个或多个 bundle

通常像GruntGulp这类的构建工具,打包思路是:先遍历源文件,而后匹配规则,最后再打包,这个过程很耗费资源。而Webpack能够作到按需加载,与其余构建工具不一样之处在于:Webpack是从入口文件开始,通过模块依赖加载、分析和打包三个流程完成项目的构建。在加载、分析和打包的三个过程当中,能够针对性的作一些解决方案,达到按需加载的目的,好比拆分公共代码(code split)等。

Webpack在打包时遵循“一切皆模块”的思想,即JS是模块,CSS等文件也是模块,还能够将ES6转为ES5,而且能够对LessSass这些CSS预处理器进行编译。在打包过程当中经过强大的Loader和插件机制来完成解决方案的封装,最后对项目进行压缩和优化等操做。Webpack解决了传统构建工具实现不了的问题,被更多的前端开发者使用。

1.三、Webpack环境搭建

1.3.一、安装Node.js

Webpack实际是用Node.js写的,因此要先安装Node.js环境。

首先进入Node.js的官网,选择对应系统下载安装包:

对于 windows 用户,直接下载安装包安装便可,若是是 Macos 用户,推荐使用 brew 进行安装。

Node.js有不少版本,包括稳定版和开发版,不一样的项目须要的Node.js版本不一样,推荐你们安装 8.x 以上的版本。

1.3.二、NPM简介与经常使用命令

(1)NPM包管理工具

简单来讲,NPM(Node Package Manager)是包含在Node.js里面的一个包管理工具,NPM会随着Node.js一块儿安装,咱们能够在命令提示符(如下演示的命令均为windows系统环境)中查看NPM的版本:

NPM为开发者提供了一个代码模块共享的大平台,当咱们项目中须要使用某个模块(JavaScript包)时,能够直接使用NPM包管理工具来下载对应的包并安装,咱们也能够把本身用Node.js写的代码发布到平台上供他人使用。

在搭建一个前端项目以前,一般会在项目的根目录下生成一个名为package.json的文件做为NPM包的描述文件,使用该文件来定义项目信息、配置包依赖关系。package.json文件能够本身手动建立,也可使用命令来建立:

npm init
复制代码

在命令提示符中输入上面命令(先 cd 到项目根目录下,再执行命令)后,会向用户提问一系列问题,根据对应的提示回答问题,若是不回答直接输入回车,程序会按照默认选项进行配置。期间使用 -f(表示force)、-y(表示yes)会跳过提问阶段,直接生成一个新的package.json文件。

文件中包含了NPM包的基本信息(项目名称、版本号、项目描述、做者)和依赖管理,例如:

{
    "name": "demo",
    "version": "1.0.0",
    "dependencies": {
        "webpack": "^4.29.6"
    }
}
复制代码

name:表示咱们当前的项目名称,若是未来发布到npmjs.com平台上,会以这个名字来命名,还有一种命名方式是@scope/name,表示做用域包。

version:是当前项目的版本,NPM是围绕 语义版本控制(semver)思想而设计的,这种规范是以 主版本号.次版本号.修订号MAJOR.MINOR.PATCH)的描述形式,其分别表示的意思是:

  • 主版本号:当你作了不兼容的API修改;
  • 次版本号:当你作了向下兼容的功能性新增;
  • 修订号:当你作了向下兼容的问题修正(例如,修改了一个bug);

dependencies:是demo这个项目中的依赖,还有devdependencies也是描述当前项目的依赖,这两者的区别咱们会在下面进行详细的说明。上面package.json示例中dependencies里存放了有关于webpack的版本号,版本号前面有个^,意思是主版本是4的最新版本,每次执行安装命令的时候,会更新符合这个规则的最新包。

(2)NPM的经常使用命令

咱们经常使用的NPM命令主要是作四种操做:安装、删除、初始化、配置。

安装某个NPM

npm install packageName
## 简写
npm i packageName
复制代码

安装package.json中的全部依赖

npm install
复制代码

安装指定版本的包

npm i packageName@x.x.x
复制代码

全局安装依赖包

npm i packageName --global
## 简写
npm ipackageName -g
复制代码

安装依赖包,而且将依赖写入package.json文件的dependencies部分

npm i packageName --save
## 简写,简写中-S是大写字母
npm i packageName -S
复制代码

安装依赖包,而且把依赖写入package.json文件的devdependencies部分

npm i packageName --save-dev
## 简写
npm i packageName -D
复制代码

删除某个NPM

npm uninstall packageName

复制代码

初始化一个NPM项目,自动生成package.json文件

npm init

复制代码

单次设置镜像,使用淘宝NPM镜像替换官方NPM镜像

因为NPM网站属于境外服务器,因此咱们为了保证下载NPM包时的网络稳定性,会将下载镜像换成国内的镜像,其中淘宝NPM镜像是国内最大的一家NPM镜像网站,在下载NPM包时,使用 cnpm 命令代替原来的 npm 命令。

npm [命令] --registry=https://registry.npm.taobao.org

复制代码

设置默认npm使用淘宝镜像

npm config set registry https://registry.npm.taobao.org

复制代码

安装cnpm包,安装成功后npm命令更换为cnpm命令

npm install -g cnpm --registry=https://registry.npm.taobao.org
## 安装成功以后,直接像使用npm同样使用cnpm便可,例如:安装某个包就变成了
cnpm i packageName

复制代码

设置环境变量

npm set xxx
## 例如:
npm set init-author-name 'Your name'

复制代码

查看某个包的信息

npm info
## 例如:
npm info lodash

复制代码

查找npm仓库

npm search
## 后面能够跟字符串或者正则表达式,例如:
npm search webpack

复制代码

树形的展现当前项目安装的全部模块,以及对应的依赖

npm list
## 例如,查看全局安装的模块:
npm list --global

复制代码

(3)dependencies 和 devDependencies 区别

在上面关于NPM经常使用命令中,咱们有讲到 dependenciesdevDependencies 的命令分别是:

# 自动把模块和版本号添加到dependencies部分,将依赖安装到生产环境
npm install module-name --save
# 自动把模块和版本号添加到devdependencies部分,将依赖安装到开发环境
npm install module-name --save-dev

复制代码

不少同窗不太理解什么是开发环境和生产环境,简单来讲,就是在项目的开发阶段就是开发环境;项目上线了,开始正式提供对外服务,在生产环境下,通常会关掉错误报告,打开错误日志等操做。

devdependencies配置的是开发环境,安装项目开发时所依赖的模块。好比像webpack工具,只是用来构建项目和打包,这些都是在开发阶段才使用的,等项目上线后就用不到webpack工具了,那么咱们就能够把webpack安装到开发环境中(使用 --save-dev命令安装到devdependencies下);

dependencies是生产环境,安装项目运行时所依赖的模块。好比jQuery库,,等项目上线之后依然是要继续使用的,咱们就要安装在生产环境中(使用 --save 命令安装到dependencies下),若是没有把须要的依赖安装到生产环境中,项目上线运行时就有可能会报错。

(4)本地模式和全局模式

咱们在安装NPM包时,有两种模式可选:一是本地模式,二是全局模式。

默认是本地模式安装,本地模式是指在执行npm install命令后,会在执行命令的目录下建立node_modules目录,而后再把下载的依赖和安装包保存到node_modules目录下。

全局模式是指将下载的依赖和安装包保存到全局路径下的方式,在Node.js中使用require依赖时,会优先查找本身当前文件中的node_modules目录,若是没有,在循环遍历上层的node_modules,若是还找不到依赖,就会去全局模式下的安装目录寻找。

package.json中增长bin字段,而且指向包内对应的文件映射路径,就能够把该文件放到PATH中,使用npm命令执行了,例如:

"bin": {
  "testCmd": "bin/cmd.js"
}

复制代码

配置好bin字段后,在项目根目录输入 npm link xxx 就能够执行testCmd命令了, 使用 npm link 命令,将 npm 模块连接到对应的运行项目中去,方便地对模块进行调试和测试 。

(5)修改NPM全局模式的默认安装路径

通常状况下,咱们安装Node.js环境,程序会自动把NPM全局模块的路径设置在系统盘(一般是C盘下),咱们在项目开发阶段不建议全局路径设置在系统盘,不但会影响电脑的性能,并且还很不安全。能够经过如下命令来设置默认下载的全局路径目录:

输入命令,查看当前配置

npm config ls

复制代码

运行结果:

若是是第一次使用NPM安装包的话,在配置中只会看到prefix的选项,就是NPM默认的全局安装目录。可是若是有屡次使用NPM安装包的话,就会看到cacheprefix两个路径,以下图:

第一步:

在欲更改的目录下新建两个文件夹,分别是:node_global_modulesnode_cache,效果如图:

第二步:

打开命令提示符,执行下面两条命令:

npm  config set prefix "D:\dev\nodejs\node_modules\npm\node_global_modules"
npm  config set cache "D:\dev\nodejs\node_modules\npm\node_cache"

复制代码

执行成功后,能够用 npm config ls 命令查看配置的结果,效果如图:

第三步:

验证配置成功后,须要配置环境变量。在环境变量中,新建一个系统变量,变量名:NODE_HOME,变量值:D:\dev\nodejs,效果如图:

Path变量名中,新建变量值:

%NODE_HOME% %NOED_HOME%\node_modules %NODE_HOME%\node_modules\npm\node_global_modules\

效果如图:

保存以后,能够从新执行全局安装命令,查看NPM依赖包在全局的默认安装目录是否为咱们配置好的目录,若是成功下载到了设置后的目录下,就成功修改了默认全局安装路径。

(6)NPM Scripts

NPM不只能够用于模块管理,还能够用于执行脚本。能够在package.json文件中添加scripts字段,用于指定脚本命令,以供NPM直接调用,示例以下:

// package.json
{
    "scripts": {
        "build": "webpack",
        "start": "node src/scripts/dev.js"
    }
}

复制代码

scripts里面放的是npm要执行的命令,格式是key-value形式,为了简化操做,具体命令为value,自定义的简化命令为key,当npm运行key命令时,等同于执行后面的value命令。例如,在package.json添加上面字段以后,能够直接使用npm run buildnpm run start命令了 ,并且npm run start命令还能够简写成npm start

注意:上面提到的简写,只有npm run start才能够简写,并非全部script命令都支持这种简写的方式。

除了 npm 外,还有一些包管理工具,主要是针对 npm 的下载速度慢、node_modules 混乱等缺点设计的,例如yarnpnpm

在后面会讲到使用create-react-app脚手架工具搭建React开发环境,在自动生成的package.json文件中配置的scripts字段内容是:

"scripts": {
  "start": "react-scripts start",
  "build": "react-scripts build",
  "test": "react-scripts test",
  "eject": "react-scripts eject"
}

复制代码

咱们在命令窗口中直接执行npm start就至关于执行了npm react-scripts start命令,经过这个命令能够启动React服务,而且在浏览器输入IP地址就能够访问React项目了。

1.3.三、安装Webpack

(1)安装Webpack

webpack的安装须要使用NPM来完成,安装命令以下:

## 全局安装
npm install -g webpack
## 安装到项目目录中
npm install --save-dev webpack

复制代码

安装好以后,就可使用webpack的命令了。

(2)安装Webpack-cli

Webpack-cliWebpackCLI (Command-line interface)工具,若是在项目中,咱们可使用下面的方式安装:

# 本地安装
npm install webpack-cli --save-dev
# 全局安装
npm install webpack-cli -g

复制代码

因为webpack是用于项目构建和打包的工具,因此咱们在安装时使用--save-dev命令把webpack-cli放到开发环境的字段下。

二、Webpack中常规配置项介绍

2.一、webpack.config.js 配置文件

当咱们安装好webpack以后,就可使用webpack命令了,好比要将一个main.js文件打包成一个bundle.js文件,可使用以下命令:

webpack main.js bundle.js

复制代码

通常在实际的项目开发中,要把这些命令写到一个webpack.config.js的文件中。上面打包操做能够作以下配置:

module.exports = {
	entry: './main.js',
	output: {
		filename: 'bundle.js'
	}
};

复制代码

在上面的配置文件中,咱们配置了项目的入口(entry)和出口(output),在该项目的关系图中,entry字段指定了入口文件,即把main.js做为起点。output字段是指定了输出位置,即指定webpack把整理后的资源放在哪里。

2.二、webpack核心概念

webpack主要有4个核心概念:

入口(entry):项目入口,也是webpack全部依赖关系图的起点。

出口(output):指定webpack打包应用程序的目录。

加载器(loader):加载须要处理的模块,对模块进行转换处理。

插件(plugins):定义项目要用到的插件。

2.2.一、webpack入口(entry)和出口(output)

在前面的内容中,咱们已经了解到了,webpack是一个模块打包工具,须要处理具备依赖关系的各个模块,这些模块会构成一个依赖关系图(dependency graph)。webpack的入口就是这张关系图的起点,指的是入口文件。webpack出口指的是须要把这张关系图导出到哪一个文件中,即导出文件。

(1)入口(entry)

entry字段指定了入口文件,也能够理解为当前项目启动时运行的第一个文件,语法为:

entry: string | object | Arrary<string>

复制代码

entry字段支持多种类型,值能够是字符串、对象、数组。简单来理解,就是entry能够指定一个文件入口,也能够指定多文件入口。咱们举例来讲明entry的用法:

单文件入口示例

// 使用key-value方式
module.exports = {
    entry: 'path/to/my/entry/main.js'
};

// 或者使用对象方式
module.exports = {
    entry: {
        main: 'path/to/my/entry/main.js'
    }
};

// entry也可使用数组指定多个入口文件路径,输出时会合并输出
module.exports = {
    mode: 'development',
    entry: ['./src/app.js', './src/home.js'],
    output: {
        filename: 'array.js'
    }
};

复制代码

多文件入口

// entry配置3个独立的入口文件,会打包成3个对应的bundle
module.exports = {
    entry: {
        home: 'path/to/my/entry/home.js',
        search: 'path/to/my/entry/search.js',
        list: 'path/to/my/entry/list.js'
    }
};

复制代码

(2)出口(output)

output字段是指定entry对应文件编译打包后的输出位置,也能够理解为指定webpack把整理好的资源放到哪里。output字段经常使用的属性有:

  • path:指定打包完成的文件存放的路径;
  • filename:指定打包完成的文件的文件名称;
  • publicPath:指定一个在浏览器中被引用的URL地址;

若是不指定path参数,将默认将打包文件输出到webpack.config.js同级目录下;若是不指定output,打包文件会默认输出到dis/main.js,即output字段的path属性默认是disfilename属性默认是main

一个webpack的配置能够包含多个entry,可是只能有一个output。对于不一样的entry能够经过output.filename占位符语法来区分,例如:

module.exports = {
    entry: {
        home: 'path/to/my/entry/home.js',
        search: 'path/to/my/entry/search.js',
        list: 'path/to/my/entry/list.js'
    },
    output: {
        filename: '[name].js',
        path: __dirname + '/dist'
    }
};

复制代码

在上面的配置中,output.filename指定的[name]就是一个占位符,对应的是entry中的keyhomesearchlist),最终输出的结果是:

path/to/my/entry/home.js → dist/home.js
path/to/my/entry/search.js → dist/search.js
path/to/my/entry/list.js → dist/list.js

复制代码

目前webpack支持的占位符有:

占位符 含义
[hash] 模块标识符的hash
[chunkhash] chunk内容的hash
[name] 模块的名称
[id] 模块标识符
[query] 模块的query,例如,文件名 ? 后面的字符串
[function] 一个 return 出一个 string 做为 filename 的函数

2.2.二、webpack 加载器(loader)

loader是解析处理器,你们都知道,webpack的任务就是把具备依赖关系的各个文件进行整合并打包,这些文件的类型有不少,好比.html.css.js.scss.jpg等等。可是webpack只认识JavaScript文件,那如何识别其余文件呢?loader就解决了这个问题。好比,不少浏览器不支持ES6语法,webpack能够经过loader配置,将ES6语法转化为ES5的语法,还能够将图片转化为base64dataURL ,还能够经过loader直接在JavaScript文件中使用import 引入csshtml

loaderwebpack构建文件的过程当中起着相当重要的做用,实现能够经过loader识别出要对哪些文件进行预处理,而后loader转换这些须要预处理的文件,并添加到bundle(构建后的模块)中。在React框架开发时,常常会用到JSX这种扩展语言来编写DOM,目前几乎全部的浏览器都不支持JSX格式,那么loader就能够在使用JSX以前作一些预处理操做,将其转化成JavaScript语言,示例以下:

module.exports = {
	entry: {
		app: './app.js'
	}
	output: {
		filename: 'bundle.js',
    	path: './dist'
	}
	module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                use: 'babel-loader'
            },
            {
                test: /\.css$/,
                use: 'css-loader'
            }
        ]
    }
}

复制代码

在上面的例子中,test字段表示要对哪些类型的文件进行构建,use字段表示要用哪些模块对该类型的文件进行构建。在test项中使用/\.css$/这种正则表达式来匹配须要处理的模块文件,即匹配以.css为后缀的文件。

在配置loader以前,use中的模块是须要安装的,命令以下:

npm install --save-dev babel-loader
npm install --save-dev css-loader

复制代码

提示:

webpack的早期版本中,loader的写法是:

module.exports = {
......
module: {
	loaders: [
		{
		  test: /\.(js|jsx)/,
		  loader: 'babel-loader'
		},
		......
	]
}
}

复制代码

webpack最新版本中已经废弃了loadersloader的写法,改为了 rulesuse

2.2.三、webpack 插件(plugin)

pluginwebpack起着重要的做用,经过plugin能够解决loader解决不了的问题,以此来丰富webpack的功能。webpack自己就是有不少插件组成的,因此内置了不少插件。除了内置插件,咱们也能够经过NPM包的方式来使用插件,好比如今须要安装一个html-webpack-plugin的插件,先执行安装命令:

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

复制代码

而后在webpack.config.js文件中配置plugins

var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: {
        app: './app.js'
    },
    output: {
        filename: 'bundle.js',
        path: './dist'
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)/,
                use: 'babel-loader'
            },
            {
                test: /\.css$/,
                use: 'css-loader'
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin()
    ]
}

复制代码

上面的示例中,plugins参数为一个数组,能够传入多个plugin,另外须要注意plugin是能够带参数的,因此plugins属性传入的必修为new实例。

三、使用Babel转换JavaScript代码

3.一、什么是Babel

Babel是一个JavaScript的编译器,咱们在webpack中可使用ES6以上版本的语法写代码,可是目前主流的浏览器仅支持ES5语法,经过Babel能够将ES6+语法自动转换成ES5语法,来适配浏览器的JavaScript解释器。

好比说,咱们使用ES6语法中的箭头函数实现代码:

(val) => (val + 1) ;

复制代码

使用Babel转化成ES5语法后:

function(val){
	return val+1 ;
}

复制代码

3.二、babel-cli命令行工具的使用

在项目中安装babel-cli,命令以下:

npm install --save-dev @babel/core @babel/cli
## 简写
npm i -D @babel/core @babel/cli

复制代码

而后再安装转换规则:

# 安装 preset-env
npm i -D @babel/preset-env
# 执行 CLI 添加--presets
npx babel babel.js --presets=@babel/preset-env

复制代码

测试babel-cli命令行工具,先建立一个app.js文件,输入下面的代码:

[1, 2, 3].map(n => n ** 2);

复制代码

而后在命令行中输入下面命令:

npx babel app.js
## 或者 指定输出结果到固定文件
npx babel app.js --out-file appout.js
## 简写
npx babel app.js -o appout.js

复制代码

转化命令执行成功后,app.js的语法就变成了ES5语法:

[1, 2, 3].map(function(n) {
    return Math.pow(n, 2);
});

复制代码

3.三、Babel配置文件

Babel还支持配置文件的方式进行转化操做,配置文件支持两种形式:

(1)使用package.jsonbabel属性

示例:

{
    "name": "demo",
    "version": "1.0.0",
    "babel": {
        "presets": ["@babel/preset-env"]
    }
}

复制代码

(2)使用.babelrc文件

在项目的根目录建立.babelrc.babelrc.js文件,Babel会在正在被转义的文件当前目录中查找一个.babelrc文件, 若是不存在,它会向外层目录遍历目录树,直到找到一个 .babelrc 文件,或一个 package.json 文件中有 "babel": {} 。 在文件中配置以下:

{
    "presets": ["@babel/preset-env"]
}

复制代码

3.四、在webpack中使用babel

第一步:安装依赖包

# 安装开发依赖
npm i webpack babel-loader webpack-cli @babel/core @babel/preset-env @babel/plugin-transform-runtime -D
# 将 runtime 做为依赖
npm i @babel/runtime -S

复制代码

第二步:建立webpack.config.js文件,配置以下:

module.exports = {
    //......
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                [
                                    '@babel/preset-env',
                                    {
                                        useBuiltIns: 'usage'
                                    }
                                ]
                            ]
                        }
                    }
                ]
            }
        ]
    }
};

复制代码

Babel配置到webpack.config.js文件的options中,或者是配置到.babelrc文件, 或者使用package.jsonbabel 字段。

四、配置webpack-dev-server本地服务器

webpack-dev-server 就是一个Express的小型服务器,经过Express的中间件 webpack-dev-middlewareWebpack进行交互的。

4.一、安装webpack-dev-server服务

在项目中安装:

npm i webpack-dev-server

复制代码

启动服务:

npx webpack-dev-server

复制代码

服务启动成功后,在浏览器中访问webpack-dev-server的默认地址 localhost:8080,就能够默认的index.html页面,若是没有该页面,就会显示文件目录。

4.二、整合Webpack

webpack-dev-server服务整合到webpack的配置文件中,webpack.config.js配置文件内容以下:

const path = require('path');
module.exports = {
    //...
    devServer: {
        contentBase: path.join(__dirname, 'dist'),
        port: 9000  //服务器端口
    }
};

复制代码

还能够将webpack-dev-server放到package.jsonscripts里面,来简化服务启动命令:

{
    "scripts": {
        "dev": "webpack-dev-server --mode development --config webpack.config.dev.js --hot --inline --port 3000"
    }
}

复制代码

配置完成后,可使用下面命令启动服务:

npm run dev

复制代码

执行npm run dev实际就是执行的对应webpack-dev-server命令。

4.三、配置热加载

热加载也叫模块热替换( Hot Module Replacement ,简称HMR),配置热加载后,在应用运行期间修改代码,不须要从新刷新页面就能够在浏览器中加载更新后的内容。 经过配置 webpack.HotModuleReplacementPlugin 插件来开启全局的 HMR 功能。

修改webpack.config.js文件,开启热加载:

const path = require('path');
module.exports = {
    entry: './src/index.js',
    devServer: {
        open: true, //自动打开浏览器
        contentBase: path.join(__dirname, 'dist'),//指定服务器将从哪一个目录去查找内容文件
        port: 9000, //服务器端口
        hot: true // 开启 hmr 支持
    },
    plugins: [
        // 添加 hmr plugin
        new webpack.HotModuleReplacementPlugin()
    ]
};

复制代码

完成上面的配置后,重启服务,在浏览器访问默认地址 http://localhost:9000 ,而后再修改JavaScript代码,就能够实时看到效果了。

若是使用webpack-dev-servercli功能只须要经过执行下面命令,就能够开启自动刷新功能:

webpack-dev-server --hot --inline

复制代码

执行上面命令会自动将webpack.HotModuleReplacementPlugin这个插件添加到 Webpack 的配置中去。这种是最简单的配置方式了。

4.四、本地服务器的常见配置项

常见配置以下:

# 修改端口号和 host
webpack-dev-server --port 3000 --host 127.0.0.1

# 启动inline 模式的自动刷新
webpack-dev-server --hot --inline

# 手动指定 webpack config 文件
webpack-dev-server --config webpack.xxx.js

# 指定 webpack 的 mode
webpack-dev-server --mode development

# watch 功能,文件发生变化则触发从新编译
webpack-dev-server --watch

# dev-server默认会将工做目录(当前目录)最为基本目录,能够手动修改它
webpack-dev-server --content-base ./build

# 查看帮助
webpack-dev-server -h

# 开启inline模式,自动刷新页面
webpack-dev-server --hot --inline

复制代码

五、配置React开发环境

5.一、使用webpack配置React环境

5.1.一、搭建React项目

建立React项目的文件夹,在项目根目录下打开命令提示符,执行初始化命令,生成package.json文件:

npm init -y

复制代码

依次执行下列命令,若是已经安装了cnpm的话,可使用cnpm替代npm命令,执行命令完成基础建立:

# 安装 react react-dom依赖
npm i react react-dom

# 安装 webpack 和 webpack-cli 开发依赖
npm i webpack webpack-cli -D

# 安装 babel
npm i babel-loader @babel/core @babel/preset-env -D

# 安装 babel preset-react
npm i @babel/preset-react -D

复制代码

建立webpack.config.js配置文件,并在配置文件中添加对JSX语法的Babel编译支持:

module.exports = {
    resolve: {
        extensions: ['.wasm', '.mjs', '.js', '.json', '.jsx']
    },
    module: {
        rules: [
            {
                test: /\.jsx?$/, // jsx/js文件的正则
                exclude: /node_modules/, // 排除 node_modules 文件夹
                use: {
                    // loader 是 babel
                    loader: 'babel-loader',
                    options: {
                        // babel 转义的配置选项
                        babelrc: false,
                        presets: [
                            // 添加 preset-react
                            require.resolve('@babel/preset-react'),
                            [require.resolve('@babel/preset-env'), {modules: false}]
                        ],
                        cacheDirectory: true
                    }
                }
            }
        ]
    }
};

复制代码

在项目根目录建立 src/App.jsx 文件,src是源文件目录,App.jsx文件内容以下:

import React from 'react';
import ReactDOM from 'react-dom';
const App = () => {
    return (
        <div> <h1>Hello React and Webpack</h1> </div>
    );
};
export default App;
ReactDOM.render(<App />, document.getElementById('app')); 复制代码

src目录下建立index.jsx文件,内容以下:

import App from './App'; // 这里能够省略.jsx

复制代码

将文件添加到webpack.config.js中的entry

module.exports = {
    entry: './src/index.jsx',
    // ...
};

复制代码

接下来在src目录下建立index.html文件,做为项目的模板,内容以下:

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="UTF-8" />
        <title>Hello React Webpack</title>
    </head>
    <body>
        <div id="app"></div>
    </body>
</html>

复制代码

须要使用 html-webpack-plugin 插件来复制 index.htmldist 文件夹下。

首先是安装 html-webpack-plugin

npm i html-webpack-plugin -D

复制代码

而后修改webpack.config.js配置:

const HtmlWebPackPlugin = require('html-webpack-plugin');
module.exports = {
    // ...
    plugins: [
        new HtmlWebPackPlugin({
            template: 'src/index.html',
            filename: 'index.html',
            inject: true
        })
    ]
};

复制代码

上面的操做都完成以后,能够执行打包命令:

npx webpack --mode development

复制代码

运行结果:

打包成功后,会在项目的根目录下自动生成dist文件夹,存放的是webpack编译打包后的文件。这时,咱们就能够把打包的命令放到package.json文件的scripts中,配置以下:

//package.json文件
{
    "scripts": {
        "build": "webpack --mode production"
    }
}

复制代码

配置好了之后,咱们就可使用简化的命令来操做打包了:

npm run build

复制代码

5.1.二、配置React项目的本地服务

(1)配置服务

第一步:安装webpack-dev-server依赖:

npm i webpack-dev-server -D

复制代码

第二步:在webpack.config.js配置文件中添加服务相关配置,完整配置以下:

//webpackage.config.js

const path = require('path');
const HtmlWebPackPlugin = require('html-webpack-plugin');
module.exports = {
    mode: 'development',
    devtool: 'cheap-module-source-map',
    devServer: {
        contentBase: path.join(__dirname, './src/'),
        publicPath: '/',
        host: '127.0.0.1',
        port: 3000,
        stats: {
            colors: true
        }
    },
    entry: './src/index.jsx',
    // 将 jsx 添加到默认扩展名中,省略 jsx
    resolve: {
        extensions: ['.wasm', '.mjs', '.js', '.json', '.jsx']
    },
    module: {
        rules: [
            {
                test: /\.jsx?$/, // jsx文件的正则
                exclude: /node_modules/, // 排除 node_modules 文件夹
                use: {
                    // loader 是 babel
                    loader: 'babel-loader',
                    options: {
                        // babel 转义的配置选项
                        babelrc: false,
                        presets: [
                            // 添加 preset-react
                            require.resolve('@babel/preset-react'),
                            [require.resolve('@babel/preset-env'), {modules: false}]
                        ],
                        cacheDirectory: true
                    }
                }
            }
        ]
    },
    plugins: [
        new HtmlWebPackPlugin({
            template: 'src/index.html',
            filename: 'index.html',
            inject: true
        })
    ]
};

复制代码

第三步:修改package.json文件的scripts配置,添加start字段:

{
    "scripts": {
        "build": "webpack --mode production",
        "start": "webpack-dev-server --mode development --open"
    }
}

复制代码

第四步:执行启动服务命令:

npm start

复制代码

服务启动成功后,会自动打开浏览器,并访问 http://127.0.0.1:3000/ ,效果如图:

(2)配置热加载

第一步:在src目录中新建dev.js文件,添加如下代码:

if (module.hot) {
    module.hot.accept(err => {
        if (err) {
            console.error('Cannot apply HMR update.', err);
        }
    });
}

复制代码

上面代码用于触发HMR,这部分代码不属于业务代码。

第二步:在webpack.config.js配置文件中添加热加载配置:

// webpack.config.dev.js

const webpack = require('webpack'); //增长导入webpack

module.exports = {
    devServer: {
    	...
		hot: true, //在devServer中增长hot字段
    	...
    },
    ...
    entry: ['./src/index.jsx', './src/dev.js'], //在entry字段中添加触发文件配置
    ...
    plugins: [
		// plugins中增长下面内容,实例化热加载插件
		new webpack.HotModuleReplacementPlugin(),
    ...
    ]
    ...
}

复制代码

第三步:启动服务,测试热加载

执行启动服务命令:

npm start

复制代码

服务启动后,会自动打开浏览器,咱们在App.js中修改内容,保存后会看到浏览器内自动更新,效果以下图:

5.二、使用create-react-app快速搭建环境

Create React AppFaceBookReact团队官方出的一个构建React单页面应用的脚手架工具。它自己集成了Webpack,并配置了一系列内置的loader和默认的npm的脚本,能够很轻松的实现零配置就能够快速开发React的应用。

create-react-appReact中最简单的建立单页面程序的方式,安装命令以下:

npm install -g create-react-app

复制代码

在须要建立项目的文件夹下启动命令提示符,使用create-react-app建立项目,命令以下:

create-react-app my-app

复制代码

上面命令中,my-app是建立的项目名称。执行 cd my-app 进入到项目根目录下,执行启动服务命令:

npm start

复制代码

服务启动成功后,会自动打开浏览器,效果如图:

到此,React项目就搭建成功了。

六、总结

咱们这个章节先经过前端的发展历程引出了为何要使用Webpack构建项目,而后经过对Webpack的常规配置、Babel转换、搭建本地服务进行了详细的讲解,最后使用Webpack搭建React开发环境。

做为一套React框架教程,对Webpack的使用有了解就能够了,因为Webpack主要是用于项目的构建和打包,甚至有的同窗在工做中根本就接触不到Webpack,或者是项目中只配置一次Webpack,后面就再也不用了。对于这些同窗来讲,但愿这篇教程可以给你带来一些新的知识储备,在之后用到的时候,可以有操做的思路和方法。

关于Webpack的知识远远比这篇教程中的内容要多,不过对于项目开发来讲,掌握这些基础知识就够用了。你们必定要培养独立思考和解决问题的能力,在项目构建过程当中,若是遇到了问题,根据所学的知识寻找解决问题的方法,经过实践来提高本身的编程能力,你们加油!

相关文章
相关标签/搜索