webpack究竟是什么?
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(static module bundler)。在 webpack 处理应用程序时,它会在内部创建一个依赖图(dependency graph),用于映射到项目需要的每个模块,然后将所有这些依赖生成到一个或多个bundle。
注:webpack不是一个JS编译器,而是模块打包工具(并不仅仅是JS模块的打包工具,还支持CSS、图片等文件);
webpack支持的JS规范主要有ES Moudule、CommonJS、CMD、AMD等。
以上规范举几个例子:
- ES2015 import 语句(ES6语法)
- CommonJS require() 语句 ==> 异步引入 ,require.resolve() ==>同步方式获取模块ID
- AMD define 和 require 语句,define导出方式不能在异步函数中调用
- css/sass/less 文件中的 @import 语句。
- 样式(url(...))或 HTML 文件中的图片链接(image url)
提高webpack打包速度的两个方法:
(1)保持node.js的版本比较新
(2)保持webpack版本比较新
这是因为新版本的webpack会利用node的新特性来提高它的打包速度。
webpack的正确安装方式
正常webpack的安装方式有两种:全局安装和本地项目安装
(1)使用以下命令行进行webpack全局安装
npm install webpack webpack-cli -g
(2)使用以下命令行进行本地项目安装
npm install webpack webpack-cli -D
以上命令相当于:
npm install webpack webpack-cli --save-dev
当要选择webpack版本时,使用npm install webpack@版本 -D进行安装,这样便可以在不同项目切换使用webpack版本。
注意:当我们有其他项目需要使用到webpack3或者比较老的版本的话,如果直接使用当前的webpack命令执行打包的话会出错,这是因为当前webpack使用的是全局安装下的webpack命令,解决方法是卸载原先在全局安装webpack和webpack-cli,在本地项目进行方式(2)安装。
检查:怎么检查安装是否成功呢?
当我们使用webpack -v时会输出如下提示说当前全局没有webpack,可以安装webpack-cli脚手架来使用
One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:
- webpack-cli (https://github.com/webpack/webpack-cli)
The original webpack full-featured CLI.
We will use "npm" to install the CLI via "npm install -D".
Do you want to install 'webpack-cli' (yes/no):
此处要想使用当前项目的webpack命令,则需要加上npx,如下:
npx webpack -v
npx webpack-cli -v
如何简单使用webpack的配置文件?
webpack底层已经帮我们封装好很多默认配置,当我们没有自己手动去配置时,则会使用默认配置,但是在一个比较复杂的项目下,我们一般希望使用根据我们需求配置好的文件来更改webpack的默认配置,简单步骤如下:
(1)创建webpack的默认配置文件webpack.config.js
(2)修改webpack的默认配置,代码如下:
const path = require('path');
module.exports = {
// 配置webpack打包的入口文件
entry: './index.js',
// 配置webpack打包的输出文件
output: {
// 配置打包完成后的文件名
filename: 'bundle.js',
// 配置打包完成后的文件存放目录(绝对路径)
path: path.resolve(__dirname, 'bundle')
}
}
(3)执行命令,进行打包
npx webpack
(4)当我们有需求不想使用webpack的默认配置文件名webpack.config.js时,比如我们可以修改为webpackConfig.js,这时如果你执行打包命令则会报错,因为webpack不识别你当前的配置文件,而使用原先的默认配置文件,所以我们需要使用以下命令让webpack以你当前配置文件为当前配置。
npx webpack --config webpackConfig.js
(5)每次打包都要执行npx命令感觉跟我们以前学的不太像,可以在npm scripts中加入对应的打包命令来代替:
"scripts": {
"bundle": "webpack"
}
接着执行如下打包命令:
npm run bunlde
注意:你一定有个疑问,我们执行打包命令为npx webpack,所以不是应该在scripts中配置成,"bundle":"npx webpack",不然会使用的全局webpack命令导致找不到?
这个是因为npm scripts的配置,因为在scripts中配置为webpack,执行打包命令后它会先在当前项目的node_modules下查找是否有webpack,没有的话再往上一级到全局node_modules去找。
webpack的三种使用方式
(1)在global全局下:
webpack index.js
(2)在当前项目文件夹:
npx webpack index.js
(3)使用webpack的配置文件+npm scripts中加入打包命令:
npm run bundle
一个疑问:原先安装webpack-cli有什么作用?
(1)让我们能够在命令行中,直接使用webpack命令
(2)在本地项目文件夹下,如果全局没有安装webpack,使用webpack会去全局查找webpack则报你没安装,而 只要你在本地项目中有装webpack,使用npx webpack可以找到本地webpack命令。
什么是loader?
当我们在打包时引入的不仅仅是js文件,比如可以是一个图片文件:
var avator = require('./avator.jpg');
如果我们还执行打包命令则会提示打包报错,因为webpack本身在默认配置下只会打包js文件,所以当我们要想打包图片文件则要引入对应的loader并配置,使得webpack支持图片打包。
webpack打包图片需要借助file-loader配置:
(1)首先在本地项目安装file-loader:
npm install file-loader -D
(2)在webpack.config.js配置使用file-loader规则:
module: {
rules: [{
// 正则匹配以.jpg结尾的文件
test: /\.jpg$/,
// 将匹配到的文件使用file-loader进行打包
use: {
loader: 'file-loader'
}
}]
}
(3)配置完成之后,使用打包命令打包:
npm run bundle
总之,webpack不能识别打包除JavaScript 之外的静态资源,需要借助各种loader来预处理文件,使之能够打包除 JavaScript 之外的任何静态资源 。
图片打包番外篇
在开始之前先看一下我们目前文件的目录结构,如下图:
import avator from './avator.jpg';
var root = document.getElementById("root");
var img = new Image();
img.src = avator;
root.append(img);
这里index.js中创建了一个img标签,并打包好的avator图片赋值到img的src上,挂载到root上显示。
接着在index.html文件中的代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>图片打包番外篇</title>
</head>
<body>
<p>图片打包番外篇</p>
<div id='root'></div>
<script src='./../dist/bundle.js'></script>
</body>
</html>
上述代码看着没问题,接下来执行打包命令,没有报错,一切看似都很ok的,但是当我们在浏览器打开index.html时看到却是这样的画面,如下图:
图片居然找不到,这是啥原因啊?
img.src = avator; //6db51315be71c2bc73d1bc8663cc1ebc.jpg
这是因为上面代码img的src属性上赋的值为打包后图片的名称加扩展名,这样子的话index.html在哪个目录下引入打包后的bundle.js,就如上面index.html在src目录下引入了bunlde.js,当执行bundle.js就去src下找打包后的图片,结果找不到。反之!如果index.html在dist目录下的时候,恰巧打包后的图片也在该目录下,所以加载出来!
解决方法如下:
方式一:
方式二:
在不改变index.html位置下,直接在index.js文件中修改代码如下:
import avator from './avator.jpg';
var root = document.getElementById("root");
var img = new Image();
img.src = "./../dist/"+avator;
console.log("./../dist/"+avator)
root.append(img);
这样的话,打包成功后,图片会被打包到dist目录下,在img的src属性下直接赋值dist目录下打包好的图片路径就可以找到图片了,然后显示在浏览器上。
使用Loader打包静态资源(图片篇)
file-loader
上面我们用到了file-loader,但是并没有比较详细的介绍这个loader,接下来就来看看file-loader的一些常用配置
(1)安装file-loader,安装时起初没注意直接安装了最新版3.0.1,但是新版本并没有将它所需的依赖也安装进来,所以后面降级到2.0.0版本
npm install file-loader@2.0.0 -D
(2)常见的选项和placeholders结合使用
use: {
loader: 'file-loader',
options: {
// placeholders 占位符
name: '[name]_[hash].[ext]',
outputPath: 'images/'
}
}
选项:
name:配置自定义文件名
outputPath:配置资源的输出目录
emitFile:只返回 public URL 但不会生成文件 ,默认值为true生成,false不生成
placeholders:占位符
[name]:资源的基本名称
[hash]: 配置文件名的加密规则(默认MD5加密)
[ext]:资源的扩展名
[path]:资源相对于context的路径
url-loader
url-loader跟file-loader很像,基本差不多,基本配置如下:
(1)安装
npm install url-loader -D
(2)快速使用
use: {
loader: 'url-loader',
options: {
// placeholders 占位符
name: '[name]_[hash].[ext]',
outputPath: 'images/',
// 20KB
limit: 20480
}
}
选项:
limit:单位为Byte,当超过这个大小限制的话就会生成文件,否则直接以base64格式嵌入url中
fallback:当文件超过limit限制时,使用对应的loader处理(默认是file-loader)
url-loader与file-loader的区别
使用url-loader适用于图片文件比较小(几KB的那种),这样的话可以直接嵌入到url中,直接在浏览器js脚本运行时就加载,不用发送请求,但是如果图片文件过大的话,脚本加载过长,首屏显示就很久。
使用file-loader适用于图片文件比较大一点的,可以解决文件引用路径的问题 ,打包后生成对应的图片文件,在打开html在浏览器运行时发送一个请求,如果图片较多,会发很多http请求,会降低页面性能 。
使用Loader打包静态资源(样式篇)
基本的样式打包过程
webpack支持打包的静态资源不仅是图片等文件,还可以是CSS、Less、Scss等样式文件,这时候就需要借助style-loader、css-loader、sass-loader来支持webpack打包,简单的例子如下:
(1)在src目录下创建index.scss,编写如下的sass样式:
body {
.avator {
width: 150px;
height: 150px;
transform: translate(100, 100);
}
}
(2)在src目录下的index.js导入scss的样式并将class添加到对应图片的dom上,代码如下:
import avator from './avator.jpg';
import './index.scss'
var root = document.getElementById("root");
var img = new Image();
img.src = avator;
// 往img上添加avatorclass
img.classList.add('avator');
root.append(img);
(3)在webpack.config.js文件中添加如下配置:
{
test: /\.scss$/,
use: [
// 从下到上执行
'style-loader',
'css-loader',
'sass-loader',
'postcss-loader'
]
}
注意:这里的loader是从下到上执行的,如果写成一行的话是从右到左执行
(4)在sass文件的样式中我们用到了transform,这个样式属性要支持各种浏览器的话要添加对应的浏览器厂商前缀,比如-webkit-等,这时我们可以借助webpack的postcss-loader来给我们自动添加厂商前缀,但是postcss-loader还需要创建自己的配置文件postcss.config.js并且加入autoprefixer插件,代码如下:
-
安装style-loader、css-loader、sass-loader、postcss-loader、node-sass、autoprefixer:
npm install -D style-loader css-loader sass-loader postcss-loader node-sass autoprefixer -
在根目录下创建postcss.config.js文件并加入如下代码:
module.exports = { plugins: [ // 导入插件 require('autoprefixer') ] }
(5)删除dist下的images文件夹和bundle.js,执行打包命令完成打包,打开html文件在浏览器运行选中对应的图片元素可以看到上面挂载了avator的class,并且在transform边上还添加了厂商前缀。
执行的大概流程
- 执行打包命令
- webpack匹配到scss样式文件
- 借助sass-loader打包
- 打包好的scss样式转给css-loader转译
- 转好的样式交给postcss-loader并借助autoprefixer插件自动添加相应的厂商前缀
- 添加好前缀的样式转给style-loader挂载到dom上的style里
嵌套scss样式问题
我们可能在scss样式文件中又导入另外一个scss样式文件,这样子的话如果按原先的执行顺序来执行,只能将第一个scss文件进行处理转译,另外一个没转译,即postcss-loader和sass-loader只执行一次,解决方法就是让这两个loader再执行一次。
相关文件代码修改如下:
(1)在src目录下创建一个avator.scss文件,编写代码如下:
body {
.avator {
width: 220px;
height: 150px;
}
}
(2)在index.scss中导入avator.scss:
@import './avator.scss';
body {
.avator {
transform: translate(100px, 100px);
}
}
(3)webpack.config.js中需要修改成如下代码配置:
{
test: /\.scss$/,
use: [
// 从下到上执行
'style-loader',
{
loader: 'css-loader',
options: {
// 让匹配到的scss样式文件都去走以下两个loader
// 用于配置「css-loader 作用于 @import 的资源之前」有多少个 loader
importLoaders: 2
}
},
'sass-loader',
'postcss-loader'
]
}
如何使用css的模块化?
(1)首先我们在前面的基础上封装一个createAvator.js,作用是创建头像,createAvator.js代码如下:
import avator from './avator.jpg';
export default function () {
var root = document.getElementById("root");
var img = new Image();
img.src = avator;
img.classList.add('avator');
root.append(img);
}
(2)在index.js中引入createAvator并调用:
import avator from './avator.jpg';
import createAvator from './createAvator';
import './index.scss';
// 调用创建头像
createAvator();
var root = document.getElementById("root");
var img = new Image();
img.src = avator;
img.classList.add('avator');
root.append(img);
这时执行打包命令,运行index.html可以看到创建的两个图片头像都引用到了index.scss中的样式,index.scss中的样式就成了全局的样式了,如何解决这个问题,让css样式模块化?
(3)要让scss样式支持css module,则需要在webpack.config.js中的css-loader中配置参数module为true:
{
test: /\.scss$/,
use: [
// 从下到上执行
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
// 设置css-loader支持css 的modules
modules: true
}
},
'sass-loader',
'postcss-loader'
]
}
(4)修改index.js中引入index.scss的方式,使用模块化的方式引入,代码如下:
import avator from './avator.jpg';
import createAvator from './createAvator';
import style from './index.scss';
createAvator();
var root = document.getElementById("root");
var img = new Image();
img.src = avator;
img.classList.add(style.avator);
root.append(img);
(5)打包运行index.html可以看到两张图片头像显示不同的样式,使用createAvator创建的头像没有使用index.scss的样式,如果要想让它也使用index.scss的样式则需要在createAvator.js中模块化导入index.scss并使用,代码如下:
import avator from './avator.jpg';
// 模块化引入index.scss,调用的时候才引用样式
import style from './index.scss';
export default function () {
var root = document.getElementById("root");
var img = new Image();
img.src = avator;
// 使img引用style中的avator样式
img.classList.add(style.avator);
root.append(img);
}
webpack如何打包字体文件?
在实际项目应用中我们可能需要用到字体的样式文件,同样webpack也支持打包我们项目所需的字体样式文件,具体步骤如下:
(1)首先到iconfont阿里图标矢量库中添加几个图标到项目中,再下载对应的字体样式文件到本地
(2)在src目录下创建font文件夹,从下载下来的字体样式文件取以eot、svg、ttf、woff结尾的文件到font文件夹
(3)在index.scss中粘贴iconfot.css中的内容,修改引入路径,代码如下:
@font-face {
font-family: "iconfont";
src: url('./font/iconfont.eot?t=1543245201565'); /* IE9*/
src: url('./font/iconfont.eot?t=1543245201565#iefix') format('embedded-opentype'), /* IE6-IE8 */
// 此处去掉了base64的一段代码
url('./font/iconfont.ttf?t=1543245201565') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('./font/iconfont.svg?t=1543245201565#iconfont') format('svg'); /* iOS 4.1- */
}
(4)在index.js中导入index.scss并创建对应的字体div,代码如下:
var root = document.getElementById('root');
import './index.scss';
// 这里的class必须是iconfont 图标的class名
root.innerHTML = '<div class="iconfont icon-changjingguanli"></div>';
(5)在webpack.config.js中添加处理eot、svg、ttf结尾的文件打包的配置,代码如下:
{
test: /\.(eot|svg|ttf)$/,
use: {
loader: 'file-loader'
}
}
(6)打包运行index.html可以看到字体显示出来了
使用plugins让打包更快捷
html-webpack-plugin--自动创建Html
在我们原先打包时,每次都要删掉dist目录下的除index.html,不能直接删除整个dist,那我们能不能在每次打包之前直接将dist目录都直接删除,打包完成后自动生成符合我们配置的index.html文件呢?
这就需要借助webpack的html-webpack-plugin了,基本使用步骤如下:
(1)安装html-webpack-plugin
npm install html-webpack-plugin -D
(2)在webpack.config.js文件中引入html-webpack-plugin:
const HtmlWebPackPlugin = require('html-webpack-plugin');
(3)在webpack.config.js中添加配置:
plugins: [
// 创建插件实例,添加各项配置
new HtmlWebPackPlugin({
// 根据index.html模板创建dist下的index.html
template: 'src/index.html'
})
]
注意:在我们直接删除dist整个目录文件夹时,webpack打包完成后悔自动添加index.html并把打包好的bundle.js引入到script标签之中。
plugin的本质就像vue或者react的生命周期函数一样,可以在webpack运行到某个时刻的时候,自动帮你做一些事。
clean-webpack-plugin--打包前自动删除文件
我们在上面一些操作中,每次都在打包前把dist下的文件手动删除,有没有好的工具可以帮我们解决打包前自动删除dist文件夹及其底下所有文件?
答案肯定是有的,需要借助webpack第三方plugin即clean-webpack-plugin,具体使用步骤如下:
(1)安装clean-webpack-plugin:
npm install clean-webpack-plugin -D
(2)在webpack.config.js文件中引入clean-webpack-plugin:
const CleanWebpackPlugin = require('clean-webpack-plugin');
(3)在webpack.config.js文件中配置plugins:
plugins: [
// 创建插件实例,添加各项配置
new HtmlWebPackPlugin({
template: 'src/index.html'
}),
// 创建实例并传入要删除的文件夹
new CleanWebpackPlugin(['dist'])
]
对于SourceMap的几个理解
对于SourceMap是什么,我们可以先做一个小实验来引出SourceMap,大概步骤如下:
(1)在src目录下将index.js代码全部去掉,添加一行代码:
consles.log("hello world"); // 这里故意将console打错
(2)在webpack.config.js中mode设置为development 会自动打开sourceMap,因此我们进行手动关闭:
// 手动将sourceMap关闭
devtool: 'none',
(3)执行打包命令,运行index.html打开控制台会报打包后的main.js的第96行代码出错,我们点击main.js就会进入到打包后的main.js中排错,但是在实际中就算修改了main.js中代码,再次打包还是错的,这是因为我们只在打包好的代码修改,并没有在源文件修改,因此我们希望控制台报错的时候给我们提示的是源文件的报错信息,这时就要借助SourcMap的功能:
// 打开sourceMap功能
devtool: 'source-map',
(4)再次执行打包,控制台可以看到报错信息是在源文件的index.js中第一行console拼错了。
sourceMap就是建立起打包之后报错的代码与源文件代码之间的映射关系,主要在devtool里面进行配置,配置参数非常多,一般只用到比较常见的几个:
- source-map:会生成.map文件用于表示与源代码的映射关系,拖慢打包速度
- inline-source-map:不再生成.map文件而是将映射关系以base64形式存在打包后的文件中的data url中
- cheap-inline-source-map:只关心源代码的报错,loader之中的报错不管,不再提示我们具体哪行哪列报错,而是只精确到行,打包速度比较快
- cheap-module-source-map:不仅源代码报错要管,还要管loader等之中的报错
- eval:在打包后的文件最后一行输出简短的报错信息,速度很快
如上,devtool中的参数可以进行叠加使用,一般这样规定:
在development模式中,devtool使用cheap-module-eval-source-map
在production模式中,devtool使用cheap-module-source-map
使用webapckDevServer提升开发效率
在我们使用webpack打包的时候,每次修改源代码文件之后都要再执行一次打包命令,这非常不方便,webpack能不能监听到源代码发生修改之后自动帮我们再次打包?
强大的webpack给我们提供了很多种方式,这里简要介绍两种:
(1)直接在package.json文件中的scripts中配置,执行npm run watch即可:
"scripts": {
"watch": "webpack --watch"
},
(2)借助webpackDevServer
-
安装webpack-dev-server
npm install webpack-dev-server -D -
在webpack.config.js文件中配置devServer:
devServer: { // 告诉服务器从哪个目录中提供内容 contentBase: './dist', // 打包结束后自动启动浏览器进入localhost:8080下的页面 open: true } -
在package.json文件中的scripts中配置,执行npm run start启动服务:
"scripts": { "bundle": "webpack", "watch": "webpack --watch", "start": "webpack-dev-server" }注意:在webpackDevServer时还可以配置代理转发,比如:
module.exports = { //... devServer: { proxy: { '/api': 'http://localhost:3000' } } };以上代理的意思是当请求到/api/xxx时会代理到请求http://localhost:3000/api/xxx,这样子使我们前端在数据mock时不需要使用Charles等代理工具。
番外篇:结合express和webpack-dev-middleware集成webpack小型server
在网上偶然看到webpack借助webpack-dev-middleware和express也可以集成类似webpackDevServer的小型Server,具体步骤如下:
(1) 安装服务所需的包和依赖:
npm install express webpack-dev-middleware -D(2)在webpack.config.js文件中配置生成新文件所指向的路径即publicPath:
// 配置webpack打包的输出文件 output: { publicPath: '/', // 配置打包完成后的文件名 filename: '[name].js', // 配置打包完成后的文件存放目录(绝对路径) path: path.resolve(__dirname, 'dist') }(3)在package.json文件中的scripts中配置:
"scripts": { "bundle": "webpack", "watch": "webpack --watch", "start": "webpack-dev-server", "server": "node server.js" }(4)在项目跟webpack.config.js同级目录下创建server.js,编写代码如下:
const express = require("express"); const webpack = require("webpack"); const webpackDevMiddleWare = require("webpack-dev-middleware"); // 引入webpack的配置文件 const config = require("./webpack.config"); // 导入配置文件创建webpack的编译器 const complier = webpack(config); // 创建基于express的node web服务器 const app = express(); // express服务集成webpack-dev-middleware中间件 app.use(webpackDevMiddleWare(complier, { // 配置生成新文件所指向的路径,需要使用相对路径 publicPath: config.output.publicPath })); // 启动sever时监听3000端口 app.listen(3000, ()=> { console.log("server is running"); })(5)执行npm run server运行服务,并在浏览器输入localhost:3000进入页面
热模块更新HotModuleReplacementPlugin
在开发过程中,特别是前端开发一些html和css样式的调整,我们并不想刷新整个浏览器的页面,只是想webpack帮我们覆盖掉我们修改的那部分html和css代码,类似于局部刷新,热模块更新HotModuleReplacementPlugin能够很好地帮我们解决这个问题,具体实现步骤如下:
(1)在webpack.config.js文件中配置处理导入css文件的打包处理方式:
{
test: /\.css$/,
use: [
// 从下到上执行
'style-loader',
'css-loader',
'postcss-loader'
]
}
(2)webpack.config.js文件中配置热更新:
// 热更新plugin是在webpack底下,所有要先引入webpack
const webpack = require('webpack');
// 在devServer中启用热更新
devServer: {
// 告诉服务器从哪个目录中提供内容
contentBase: './dist',
// 打包结束后自动启动浏览器进入localhost:8080下的页面
open: true,
port: 8080,
// 启用热模块更新
hot: true,
// 在html出现问题时不让webpack帮我们自动刷新,而是直接给我们报错
hotOnly: true
}
// 在plugins下创建plugin实例
new webpack.HotModuleReplacementPlugin()
(3)在src目录下新建style.css文件,代码如下:
div:nth-of-type(odd) {
background: blue;
}
(4)src下新建index.js,代码如下:
import './style.css';
var btn = document.createElement('button');
btn.innerHTML = '新增';
document.body.appendChild(btn);
btn.onclick = function() {
var div = document.createElement('div');
div.innerHTML = 'item';
document.body.appendChild(div);
}
(5)执行npm run start启动服务,浏览器中点击新增按钮,发现奇数行的div为蓝色,我们修改style.css的background颜色为green
div:nth-of-type(odd) {
background: green;
}
保存时回到浏览器发现创建的item个数还在,item的颜色也变成了绿色,实现css模块热更新。
注意:有时候我们在js中要想实现js模块热更新,webpack也有对应的解决方式,如下例子:
(1)在src下新建counter .js、number.js和number1.js:
// counter .js
function counter() {
var div = document.createElement('div');
div.setAttribute('id', 'counter');
div.innerHTML = 1;
div.onclick = function() {
div.innerHTML = parseInt(div.innerHTML, 10) + 1
}
document.body.appendChild(div);
}
export default counter;
// number.js
function number() {
var div = document.createElement('div');
div.setAttribute('id', 'number');
div.innerHTML = 4000;
document.body.appendChild(div);
}
export default number;
// number1.js
function number1() {
var div = document.createElement('div');
div.setAttribute('id', 'number1');
div.innerHTML = 1000;
document.body.appendChild(div);
}
export default number1;
(2)清除index.js的代码添加如下代码:
import counter from './counter';
import number from './number';
import number1 from './number1';
counter();
number();
number1();
if(module.hot) {
module.hot.accept('./number', () => {
// 先将id选择器为number移除
document.body.removeChild(document.getElementById('number'));
// 创建div并设置id为number
number();
})
module.hot.accept('./number1', () => {
document.body.removeChild(document.getElementById('number1'));
number1();
})
}
(3)webpack.config.js中的热更新已配置好,直接运行服务,浏览器打开先点击几下counter的计数器后修改number.js和number1.js中的div.innerHTML值,可以发现页面上number和number1的值都会变化但是counter值还是保持在原先的计数值,并不会恢复成0。
在webpack下使用Babel处理ES6语法
现在ES6的一些语法已经逐渐代替了老版本的语法,但是一些浏览器还不能兼容ES6的一些新语法,使用Babel可以将ES6语法转换成ES5语法再让浏览器执行。
在webpack中使用Babel处理ES6的步骤如下:
(1)首先在index.js中编写需要转译的ES6代码:
const arr = [
new Promise(() => {}),
new Promise(() => {})
];
arr.map(item => {
console.log(item);
});
(2)安装babel-loader、 @babel/core、@babel/preset-env、@babel/polyfill:
npm install babel-loader @babel/core @babel/preset-env @babel/polyfill -D
(3)配置webpack.config.js文件:
// 在module下配置
{
test: /\.js$/,
// 排除node_modules目录下的js文件
exclude: /node_modules/,
loader: "babel-loader",
options: {
"presets": [["@babel/preset-env", {
// 配置babel/polyfill根据业务代码所用到的变量、函数才填充进去,这样打包的文件就比较小
useBuiltIns: 'usage'
}]]
}
}
注意:这里的babel-loader只是建立起webpack与babel转译器的桥梁,我们还需要告诉webpack编译的规则和环境,因此如上要配置presets
(4)如果此时直接执行npx webpack打包的话,发现打包后文件的末尾index.js代码还是有一些变量、函数没有被转译,因此还需要在index.js导入@babel/polyfill弥补低版本浏览器一些变量、函数 :
// index.js
// @babel/polyfill可以弥补低版本浏览器一些变量、函数
import "@babel/polyfill";