webpack

webpack

webpack 是什么?

  • 官⽅方⽹网站:https://webpack.js.org/
  • 中⽂文⽹网站:https://www.webpackjs.com/

在这里插入图片描述

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

全局安装-不推荐

webpack 是一个使用 Node.js 实现的一个模块化代码打包工具。所以,我们需要先安装 webpack,安装之前需要搭建好 Node.js 环境
安装webpack V4+版本时,需要额外安装webpack-cli

 npm install -D webpack webpack-cli -g

检查版本

 webpack -v

卸载

npm uninstall webpack webpack-cli -g

注:不推荐全局安装 ,全局安装webpack,这会将你项⽬中的webpack锁定到指定版本,造成不
同的项⽬中因为webpack依赖不同版本⽽导致冲突,构建失败

webpack-cli : 提供 webpack 命令、工具,类似 create-react-app

webpack : webpack 代码,类似 react

项⽬中安装 推荐

安装最新的稳定版本

npm i -D webpack

安装指定版本

npm i -D webpack@<version>

安装最新的体验版本 可能包含bug,不要⽤于⽣产环境

npm i -D webpack@beta

安装webpack V4+版本时,需要额外安装webpack-cli

npm i -D webpack-cli

执⾏构建
可以编辑 package.jsonscripts 来简化输入

// package.json
{
	...,
	"scripts": {
		"start": "webpack"	// scripts 中可以定位到 ./node_modules/.bin/ 目录下
	}
}

scripts 中使用 teststartrestartstop 命名的时候,可以在调用的时候省略 run,即直接 npm start

当然,还可以使用更加方便的方式:

npx webpack

通过 npx 也可以帮助我们定位命令到 ./node_modules/.bin/ 目录下

注:npm5.2+ 增加,如果没有,可以使用 npm i -g npx 来安装

打包模块

打包之前,我们需要了解一个概念,入口文件

入口文件

入口文件就是我们项目中加载的第一个文件,比如上面的 main.js 文件,其它文件都是通过 import 等方式引入的,webpack 会从我们指定的入口文件开始分析所有需要依赖的文件,然后把打包成一个完整文件。

打包命令

webpack ./js/index.js

上面命令会使用 webpack 默认的一些配置对模块文件进行打包,并把打包后的文件输出到默认创建的 ./dist 目录下,打包后的文件名称默认为 main.js

模块文件打包以后,就可以在不支持 es6 模块语法的浏览器环境下引入使用了。

打包文件分析

  • 把分散的模块文件打包到一个文件中,不需要外部引入了
  • 内置了一个小型模块加载器(类似 requireJS),实现了打包后的代码隔离与引用

以上就是 webpack 最基础的使用于基本原理,当然强大的 webpack 远远不止这些功能。

打包配置

虽然,我们可以直接通过命令的来打包,但是推荐创建一个 webpack.config.js 的配置文件来实现更方便和强大的功能。

webpack 命令在运行的时候,默认会读取运行命令所在的目录下的 webpack.config.js 文件,通常我们会在项目的根目录下运行命令和创建配置文件。

我们也可以通过 —config 选项来指定配置文件路径:

webpack --config ./configs/my_webpack.config.js

通常情况下,我们的项目目录大致如下:

/
-- /dist - 项目打包后存放目录
-- /node_modules - 第三方模块
-- /src
------ css/
------ images/
------ js/
------ index.js
-- webpack.config.js
-- package.json

配置文件

    const path = require("path");
	module.exports = {
		//上下文 项目打包的的相对路径 ,一般不用管
		context:"", // 默认值:process.pwd()
		// 必填 webpack执⾏构建⼊⼝。字符串、数组、对象
		entry: "./src/index.js",
		output: {
			// 将所有依赖的模块合并输出到main.js
			filename: "main.js",
			// 输出⽂件的存放路径,必须是绝对路径
			path: path.resolve(__dirname, "./dist")
 		}
	};

核心配置

webpack.config.js配置基础结构

module.exports = {
	entry: "./src/index.js", //打包⼊⼝⽂件
	output: "./dist", //输出结构
	mode: "production", //打包环境
	module: {
		rules: [
			//loader模块处理
 			{
				test: /\.css$/,
				use: "style-loader"
 			}
 		]
 	},
	plugins: [new HtmlWebpackPlugin()] //插件配置
};

模式 : "production" | "development" | "none"

module.exports = {
  mode: 'production'
}

1chunk = 1bundles

entry

指定打包⼊口⽂文件,有三种不同的形式:string | array | object

字符串 | 一对一:一个入口、一个打包文件

module.exports = {
  entry: './src/index.js'
}
等价与 :
module.exports = {
  entry:{ 
  	main:'./src/index.js'
  }
}

数组 | 多对一:多个入口、一个打包文件

module.exports = {
  entry: [
    './src/index1.js',
    './src/index2.js',
  ]
}

对象 |多对多:多个入口、多打包文件

module.exports = {
  entry: {
    index1: "./src/index1.js",
    index2: "./src/index2.js"
  }
}

output

打包后的文件位置

module.exports = {
  ...,
  output: {
  		path: path.resolve(__dirname, "dist"),
    	//filename: "bundle.js",
		filename: "[name].js" 
		// 占位符  
		//hash 
		//chunkhash 整个项目的hash值,每次构建一次 就会有一个新的hash
		//name 
		//id
	}
}
  • 可以指定一个固定的文件名称,如果是多入口多出口(entry 为对象),则不能使用单文件出口,需要使用下面的方式
  • 通过 webpack 内置的变量占位符:[name]

深入

webpack 中,有一个很重要的特性:模块不仅仅只是 js 的文件,webpack 可以把任意文件数据作为模块进行处理,包括:非 js 文本、css、图片等等

import txt from './a.txt';
console.log(txt);

但是 webpack 默认情况下只能处理 js 模块,如果需要处理其它类型的模块,则需要使用它提供的一些其它功能

执行简要流程

entry
loaders
plugins
output
  • loaderswebpack 中灰常核心的内容之一,前面我们说的非 js 类型的模块处理就靠它了,不同类型的模块的解析就是依赖不同的 loader 来实现的
  • pluginswebpack 中另外一个核心的内容,它主要是扩展 webpack 本身的一些功能,它们会运行在各种模块解析完成以后的打包编译阶段,比如对解析后的模块文件进行压缩等

Loaders

https://webpack.js.org/loaders/

module.exports = {
  ...,
  module: {
  	rules:[
  		{
  			test:/\.xxx$/,
       	use:{
        	loader: 'xxx-load'
      	}
			}
  	]
	}
}

webpack 碰到不识别的模块的时候,webpack 会在配置的 module 中进行该文件解析规则的查找

  • rules 就是我们为不同类型的文件定义的解析规则对应的 loader,它是一个数组
  • 每一种类型规则通过 test 选项来定义,通过正则进行匹配,通常我们会通过正则的方式来匹配文件后缀类型
  • use 针对匹配到文件类型,调用对应的 loader 进行处理

从一个简单的案例来了解 loader

我是 txt 的内容
# 我是 md 的内容
import txtData from './datas/data.txt';
import mdData from './datas/data.md';

console.log('txtData: ', txtData);
console.log('mdData: ', mdData);

默认情况下,webpack 会报错,因为 webpack 处理不了 txt 和 md 这样的非 js 的模块,但是我们可以通过专门来处理纯文本内容(不同的 loader 有不同的作用)

raw-loader

在 webpack 中通过 import 方式导入文件内容,loader 并不是 webpack 内置的,所以首先要安装

npm install --save-dev raw-loader

然后在 webpack.config.js 中进行配置

module.exports = {
  ...,
  module: {
      rules: [
      {
        test: /\.(txt|md)$/,
        use: 'raw-loader'
    	}
    ]
	}
}

file-loader

把识别出的资源模块,移动到指定的输出⽬目录,并且返回这个资源在输出目录的地址(字符串)

npm install --save-dev file-loader
rules: [
  ...,
	{
		test: /\.(png|jpe?g|gif)$/,
    use: {
      loader: "file-loader",
      options: {
        // placeholder 占位符 [name] 源资源模块的名称
        // [ext] 源资源模块的后缀
        name: "[name]_[hash].[ext]",
        //打包后的存放位置
        outputPath: "./images"
        // 打包后文件的 url
        publicPath: './images',
      }
    }
	}
]

占位符:https://webpack.js.org/loaders/file-loader#placeholders

url-loader

可以处理理 file-loader 所有的事情,但是遇到图片格式的模块,可以选择性的把图片转成 base64 格式的字符串,并打包到 js 中,对⼩体积的图片⽐较合适,⼤图⽚不合适。

npm install --save-dev url-loader
rules: [
  ...,
	{
		test: /\.(png|jpe?g|gif)$/,
    use: {
      loader: "url-loader",
      options: {
        // placeholder 占位符 [name] 源资源模块的名称
        // [ext] 源资源模块的后缀
        name: "[name]_[hash].[ext]",
        //打包后的存放位置
        outputPath: "./images"
        // 打包后文件的 url
        publicPath: './images',
        // 小于 100 字节转成 base64 格式
        limit: 100
      }
    }
	}
]

css-loader

Css-loader 分析css模块之间的关系,并合成⼀个css
Style-loader 会把css-loader⽣成的内容,以style挂载到⻚⾯的
heade部分
css-loader 生成的内容,用 style 标签挂载到⻚面的 head

分析 css 模块之间的关系,并合成⼀个 css

npm install --save-dev css-loader
rules: [
  ...,
	{
		test: /\.css$/,
    use: {
      loader: "css-loader",
      options: {
  			// 启用/禁用 url() 处理
  			url: true,
  			// 启用/禁用 @import 处理
  			import: true,
        // 启用/禁用 Sourcemap
        sourceMap: false
      }
    }
	}
]

style-loader

npm install --save-dev style-loader
rules: [
  ...,
	{
		test: /\.css$/,
    use: ["style-loader", "css-loader"]
	}
]

同一个任务的 loader 可以同时挂载多个,处理顺序为:从右到左,也就是先通过 css-loader 处理,然后把处理后的 css 字符串交给 style-loader 进行处理

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

sass-loader

sass 语法转换成 css ,依赖 node-sass 模块

npm install --save-dev sass-loader node-sass

Postcss-loader

样式⾃动添加前缀:https://caniuse.com/

npm i postcss-loader autoprefixer -D

新建postcss.config.js
//webpack.config.js

{
	test: /\.css$/,
	开课吧web全栈架构师
	use: ["style-loader", "css-loader", 		"postcssloader"]
},
//postcss.config.js
module.exports = {
	plugins: [
	require("autoprefixer")({
	overrideBrowserslist: ["last 2 versions",
	">1%"]
 })
 ]
};

loader 处理webpack不⽀持的格式⽂件,模块
⼀个loader只处理⼀件事情
loader有执⾏顺序

Plugins

扩展 webpack 本身的一些功能,它们会运行在各种模块解析完成以后的打包编译阶段,比如对解析后的模块文件进行压缩等

HtmlWebpackPlugin

在打包结束后,⾃动生成⼀个 html ⽂文件,并把打包生成的 js 模块引⼊到该 html

npm install --save-dev html-webpack-plugin
// webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
	...
  plugins: [
     new HtmlWebpackPlugin({
       title: "My App",
       filename: "app.html",
       template: "./src/html/index.html"
     }) 
  ]
};
<!--./src/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">
    //默认支持ejs模板语法
    <title><%=htmlWebpackPlugin.options.title%></title>
</head>
<body>
    <h1>html-webpack-plugin</h1>
</body>
</html>

html 模板中,可以通过 <%=htmlWebpackPlugin.options.XXX%> 的方式获取配置的值

更多的配置

  • title: ⽤来生成⻚面的 title 元素
  • filename: 输出的 HTML ⽂件名,默认是 index.html, 也可以直接配置子目录
  • template: 模板⽂件路径,⽀持加载器(loader),⽐如 html!./index.html
  • inject: true | 'head' | 'body' | false,注⼊所有的资源到特定的 template 或者 templateContent 中,如果设置为 true 或者 body,所有的 javascript 资源将被放置到 body 元素的底部,'head' 将放置到 head 元素中
  • favicon: 添加特定的 favicon 路径到输出的 HTML 文件中
  • minify: {} | false, 传递 html-minifier 选项给 minify 输出
  • hash: true | false,如果为 true,将添加 webpack 编译生成的 hash 到所有包含的脚本和 CSS ⽂件,对于解除 cache 很有用
  • cache: true | false,如果为 true,这是默认值,仅在文件修改之后才会发布文件
  • showErrors: true | false,如果为 true,这是默认值,错误信息会写入到 HTML ⻚面中
  • chunks: 允许只添加某些块 (⽐如,仅 unit test 块)
  • chunksSortMode: 允许控制块在添加到⻚面之前的排序方式,⽀持的值:'none' | 'default' |{function}-default:'auto'
  • excludeChunks: 允许跳过某些块,(⽐如,跳过单元测试的块)

clean-webpack-plugin

删除(清理)构建目录

npm install --save-dev clean-webpack-plugin
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
module.exports = {
	...
  plugins: [
    ...,
    new CleanWebpackPlugin(),
    ...
  ]
}

mini-css-extract-plugin

提取 CSS 到一个单独的文件中

npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
	...,
  module: {
  	rules: [
  		{
  			test: /\.s[ac]ss$/,
  			use: [
  				{
  					loader: MiniCssExtractPlugin.loader
					},
          'css-loader',
          'sass-loader'
        ]
			}
  	]
	},
  plugins: [
    ...,
    new MiniCssExtractPlugin({
    	filename: '[name].css'
    }),
    ...
  ]
}

sourceMap

我们实际运行在浏览器的代码是通过 webpack 打包合并甚至是压缩混淆过的代码,所生成的代码并不利于我们的调试和错误定位,我们可以通过 sourceMap 来解决这个问题,sourceMap 本质是一个记录了编译后代码与源代码的映射关系的文件,我们可以通过 webpackdevtool 选项来开启 sourceMap

module.exports = {
  mode: 'production',
  devtool: 'source-map',
  ...
}

首先,编译后会为每一个编译文件生成一个对应的 .map 文件,同时在编译文件中添加一段对应的 map 文件引入代码

...
//# sourceMappingURL=xx.js.map
...
/*# sourceMappingURL=xx.css.map*/

同时,现代浏览器都能够识别 sourceMap 文件,如 chrome,会在 Sources 面板中显示根据编译文件与对应的 map 文件定位到源文件中,有利于我们的调试和错误定位
图

webpack⽀持第三⽅字体

处理字体 https://www.iconfont.cn/?spm=a313x.7781069.1998910419.d4d0a486a

//css
@font-face {
font-family: "webfont";
font-display: swap;
src: url("webfont.woff2") format("woff2");
}
body {
background: blue;
font-family: "webfont" !important; }
//webpack.config.js
{
test: /\.(eot|ttf|woff|woff2|svg)$/,
use: "file-loader"
}

WebpackDevServer

每次的代码修改都需要重新编译打包,刷新浏览器,特别麻烦,我们可以通过安装 webpackDevServer 来改善这方面的体验

npm install --save-dev webpack-dev-server

启动命令:

npx webpack-dev-server

或者,package.json 中添加 scripts

...,
"scripts": {
  "server": "webpack-dev-server"
}

修改 webpack.config.js

module.exports = {
  ...,
  devServer: {
  	// 生成的虚拟目录路径
  	contentBase: "./dist",
  	// 自动开启浏览器
  	open: true,
  	// 端口
  	port: 8081
	}
}

启动服务以后,webpack 不在会把打包后的文件生成到硬盘真实目录中了,而是直接存在了内存中(同时虚拟了一个存放目录路径),后期更新编译打包和访问速度大大提升

Proxy

当下前端的开发都是前后端分离开发的,前端开发过程中代码会运行在一个服务器环境下(如当前的 WebpackDevServer),那么在处理一些后端请求的时候通常会出现跨域的问题。WebpackDevServer 内置了一个代理服务,通过内置代理就可以把我们的跨域请求转发目标服务器上(WebpackDevServer 内置的代理发送的请求属于后端 - node,不受同源策略限制),具体如下:

const Koa = require('koa');
const KoaRouter = require('koa-router');

const app = new Koa();
const router = new KoaRouter();

router.get('/api/info', async ctx => {
    ctx.body = {
        username: 'zMouse',
        gender: 'male'
    }
})

app.use( router.routes() );
app.listen(8787);
axios({
  url: 'http://localhost:8787/api/info'
}).then(res => {
  console.log('res',res.data);
})

默认情况下,该代码运行以后会出现跨域请求错误,修改 webpack 配置

module.exports = {
  ...,
  devServer: {
  	// 生成的虚拟目录路径
  	contentBase: "./dist",
  	// 自动开启浏览器
  	open: true,
  	// 端口
  	port: 8081,
  	proxy: {
      '/api': {
      	target: 'http://localhost:8787'
    	}
    }
	}
}

通过 proxy 设置,当我们在当前 WebpackDevServer 环境下发送以 /api 开头的请求都会被转发到 http://localhost:8787 目标服务器下

axios({
  //url: 'http://locahost:8081/api/info',
  url: '/api/info'
}).then(res => {
  console.log('res',res.data);
})

注意 url 地址要填写 WebpackDevServer 域,比如当前 WebpackDevServer 开启的是 http://localhost:8081,也就是我们当前前端代码运行的环境,那么请求的 url 也必须发送到这里,当我们的请求满足了 proxy 中设置的 /api 开头,那么就会把请求转发到 target ,所以最后的实际请求是:http://lcoahost:8787/api/info

本地mock,解决跨域:

联调期间,前后端分离,直接获取数据会跨域,上线后我们使⽤
nginx转发,开发期间,webpack就可以搞定这件事
启动⼀个服务器,mock⼀个接⼝:

// npm i express -D
// 创建⼀个server.js 修改scripts "server":"node
server.js"
//server.js
const express = require('express')
const app = express()
app.get('/api/info', (req,res)=>{
 res.json({
 name:'开课吧',
 age:5,
 msg:'欢迎来到开课吧学习前端⾼级课程'
 })
})
app.listen('9092')
//node server.js
http://localhost:9092/api/info

项⽬中安装axios⼯具

//npm i axios -D
//index.js
import axios from 'axios'
axios.get('http://localhost:9092/api/info').then(res
=>{
 console.log(res)
})
会有跨域问题

修改webpack.config.js 设置服务器代理

proxy: {
 "/api": {
 target: "http://localhost:9092"
 }
 }

修改index.js

axios.get("/api/info").then(res => {
 console.log(res);
});

Hot Module Replacement

在之前当代码有变化,我们使用的 live reload,也就是刷新整个页面,虽然这样为我们省掉了很多手动刷新页面的麻烦,但是这样即使只是修改了很小的内容,也会刷新整个页面,无法保持页面操作状态。HMR 随之就出现了,它的核心的局部(模块)更新,也就是不刷新页面,只更新变化的部分

module.exports = {
  ...,
  devServer: {
  	// 生成的虚拟目录路径
  	contentBase: "./dist",
  	// 自动开启浏览器
  	open: true,
  	// 端口
  	port: 8081,
  	// 开启热更新
  	hot:true,
  	// 即使 HMR 不生效,也不去刷新整个页面(选择开启)
    hotOnly:true,
  	proxy: {
      '/api': {
      	target: 'http://localhost:8787'
    	}
    }
	}
}

开启 HMR 以后,当代码发生变化,webpack 即会进行编译,并通过 websocket 通知客户端(浏览器),我们需要监听处理来自 webpack 的通知,然后通过 HMR 提供的 API 来完成我们的局部更新逻辑

export default function() {
    console.log('start1!');
}
import fn1 from './fn1.js';
box1.onclick = fn1;

if (module.hot) {//如果开启 HMR
    module.hot.accept('./fn1.js', function() {
      // 更新逻辑
      box1.onclick = fn1;
    })
}

上面代码就是 当 ./fn1.js 模块代码发生变化的时候,把最新的 fn1 函数绑定到 box1.onclick 上

从上面就可以看到,HMR 其实就是以模块为单位,当模块代码发生修改的时候,通知客户端进行对应的更新,而客户端则根据具体的模块来更新我们的页面逻辑(这些逻辑需要自己去实现),好在当前一些常用的更新逻辑都有了现成的插件

css热更新

样式热更新比较简单,style-loader 中就已经集成实现了,我们只需要在 use 中使用就可以了

react 热更新

  • https://github.com/gaearon/react-hot-loader

  • react 脚手架中也有集成

vue 热更新

  • https://github.com/vuejs/vue-loader
  • vue 脚手架中也有集成

Babel处理ES6

官⽅⽹站:https://babeljs.io/
中⽂⽹站:https://www.babeljs.cn/
Babel是JavaScript编译器,能将ES6代码转换成ES5代码,让我们
开发过程中放⼼使⽤JS新特性⽽不⽤担⼼兼容性问题。并且还可以
通过插件机制根据需求灵活的扩展。
Babel在执⾏编译的过程中,会从项⽬根⽬录下的.babelrc JSON
⽂件中读取配置。没有该⽂件会从loader的options地⽅读取配
置。
测试代码

//index.js
const arr = [new Promise(() => {}), new Promise(()
=> {})];
arr.map(item => {
 console.log(item);
});

安装

npm i babel-loader @babel/core @babel/preset-env -D
1.babel-loader是webpack 与 babel的通信桥梁,不会做把es6转成
es5的⼯作,这部分⼯作需要⽤到@babel/preset-env来做
2.@babel/preset-env⾥包含了es,6,7,8转es5的转换规则

Ecma 5 6 7 8… 草案(评审通过的,还有未通过的)
⾯向未来的
env是babel7之后推⾏的预设插件
env{
//index.js
const arr = [new Promise(() => {}), new Promise(()
=> {})];
arr.map(item => {
console.log(item);
});
npm i babel-loader @babel/core @babel/preset-env -D
ecma 5
ecma 6
ecma 7
ecma 8
。。。
}
Webpack.config.js

{
 test: /\.js$/,
 exclude: /node_modules/,
 use: {
 loader: "babel-loader",
 options: {
 presets: ["@babel/preset-env"]
 }
 } }

通过上⾯的⼏步 还不够,默认的Babel只⽀持let等⼀些基础的特性
转换,Promise等⼀些还有转换过来,这时候需要借助
@babel/polyfill,把es的新特性都装进来,来弥补低版本浏览器中
缺失的特性

@babel/polyfill

以全局变量的⽅式注⼊进来的。windows.Promise,它会造成全局
对象的污染

npm install --save @babel/polyfill
//index.js 顶部
import "@babel/polyfill";

按需加载,减少冗余

会发现打包的体积⼤了很多,这是因为polyfill默认会把所有特性注
⼊进来,假如我想我⽤到的es6+,才会注⼊,没⽤到的不注⼊,从
⽽减少打包的体积,可不可以呢
当然可以
修改Webpack.config.js

options: {
 presets: [
 [
 "@babel/preset-env",
 {
 targets: {
 edge: "17",
 firefox: "60",
 chrome: "67",
 safari: "11.1"
 },
 corejs: 2,//新版本需要指定核⼼库版本
 useBuiltIns: "usage"//按需注⼊
 }
 ]
 ]
 }

useBuiltIns选项是babel 7的新功能,这个选项告诉babel如何
配置@babel/polyfill。 它有三个参数可以使⽤: ①entry: 需要
在webpack的⼊⼝⽂件⾥import "@babel/polyfill"⼀
次。babel会根据你的使⽤情况导⼊垫⽚,没有使⽤的功能不会被
导⼊相应的垫⽚。 ②usage: 不需要import,全⾃动检测,但是要
安装@babel/polyfill。(试验阶段) ③false: 如果你import
“@babel/polyfill”,它不会排除掉没有使⽤的垫⽚,程序体积会
庞⼤。(不推荐)
请注意: usage 的⾏为类似 babel-transform-runtime,不会造成
全局污染,因此也会不会对类似 Array.prototype.includes() 进⾏
polyfill。

扩展:

babelrc⽂件:
新建.babelrc⽂件,把options部分移⼊到该⽂件中,就可以了

//.babelrc
{
 presets: [
 [
 "@babel/preset-env",
 {
 targets: {
 edge: "17",
 firefox: "60",
 chrome: "67",
 safari: "11.1"
 },
 corejs: 2, //新版本需要指定核⼼库版本
 useBuiltIns: "usage" //按需注⼊
 }
 ]
 ]
}
//webpack.config.js
{
 test: /\.js$/,
 exclude: /node_modules/,
 loader: "babel-loader"
}

配置React打包环境

安装

npm install react react-dom --save

编写react代码:

//index.js
import React, { Component } from "react";
import ReactDom from "react-dom";
class App extends Component {
 render() {
 return <div>hello world</div>;
 }
}
ReactDom.render(<App />,
document.getElementById("app"));

安装babel与react转换的插件:

npm install --save-dev @babel/preset-react

在babelrc⽂件⾥添加:

{
 "presets": [
 [
 "@babel/preset-env",
 {
 "targets": {
 "edge": "17",
 "firefox": "60",
 "chrome": "67",
 "safari": "11.1",
 "Android":"6.0"
 },
 "useBuiltIns": "usage", //按需注⼊
 }
 ],
 "@babel/preset-react"
 ]
}

如果是库的作者的话,提供模块的时候代码怎么打包的?
构建速度会越来越慢,怎么优化

扩展: 多⻚⾯打包通⽤⽅案

entry:{
 index:"./src/index",
 list:"./src/list",
 detail:"./src/detail"
}
new htmlWebpackPlugins({
 title: "index.html",
 template: path.join(__dirname,
"./src/index/index.html"),
 filename:"index.html",
 chunks:[index]
})

1.⽬录结构调整
src
index
index.js
index.html
list
index.js
index.html
detail
index.js
index.html
2.使⽤ glob.sync 第三⽅库来匹配路径

npm i glob -D
const glob = require("glob")
//MPA多⻚⾯打包通⽤⽅案
const setMPA = () => {
 const entry = {};
 const htmlWebpackPlugins = [];
 
 return {
 entry,
 htmlWebpackPlugins
 };
};
const { entry, htmlWebpackPlugins } = setMPA();
const setMPA = () => {
 const entry = {};
 const htmlWebpackPlugins = [];
 const entryFiles = glob.sync(path.join(__dirname,
"./src/*/index.js"));
 entryFiles.map((item, index) => {
 const entryFile = entryFiles[index];
 const match =
entryFile.match(/src\/(.*)\/index\.js$/);
 const pageName = match && match[1];
 entry[pageName] = entryFile;
 htmlWebpackPlugins.push(
 new htmlWebpackPlugin({
 title: pageName,
 template: path.join(__dirname,
`src/${pageName}/index.html`),
 filename: `${pageName}.html`,
 chunks: [pageName],
 inject: true
 })
 );
 });
 return {
 entry,
 htmlWebpackPlugins
  };
};
const { entry, htmlWebpackPlugins } = setMPA();
module.exports = {
 entry,
 output:{
 path: path.resolve(__dirname, "./dist"),
 filename: "[name].js"
 }
 plugins: [ // ...
 ...htmlWebpackPlugins//展开数组
 ]
}

扩展 @babel/plugin-transform-runtime

当我们开发的是组件库,⼯具库这些场景的时候,polyfill就不适合
了,因为polyfill是注⼊到全局变量,window下的,会污染全局环
境,所以推荐闭包⽅式:@babel/plugin-transform-runtime,它
不会造成全局污染

安装

npm install --save-dev @babel/plugin-transformruntime
npm install --save @babel/runtime

修改配置⽂件:注释掉之前的presets,添加plugins

options: {
 presets: [
 [
 "@babel/preset-env",
 {
 targets: {
 edge: "17",
 firefox: "60",
 chrome: "67",
 safari: "11.1"
 },
 useBuiltIns: "usage",
 corejs: 2
 }
 ]
 ],
"plugins": [
 [
 "@babel/plugin-transform-runtime",
 {
 "absoluteRuntime": false,
 "corejs": false,
 "helpers": true,
 "regenerator": true,
 "useESModules": false
 }
 ]
 ]
}

⽂件监听

轮询判断⽂件的最后编辑时间是否变化,某个⽂件发⽣了变化,并
不会⽴刻告诉监听者,先缓存起来
webpack开启监听模式,有两种

1.启动webpack命令式 带上--watch 参数,启动监听后,需要⼿动
刷新浏览器
scripts:{
 "watch":"webpack --watch"
}
2.在配置⽂件⾥设置 watch:true
watch: true, //默认false,不开启
 //配合watch,只有开启才有作⽤
 watchOptions: {
 //默认为空,不监听的⽂件或者⽬录,⽀持正则
 ignored: /node_modules/,
 //监听到⽂件变化后,等300ms再去执⾏,默认300ms,
 aggregateTimeout: 300,
 //判断⽂件是否发⽣变化是通过不停的询问系统指定⽂件有没有
变化,默认每秒问1次
 poll: 1000 //ms
 }
 轮询 1s查看1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值