- webpack核心
- 搭建webpack项目
- 基本配置
- 创建webpack.config.js的原因
- webpack默认配置文件如果不叫webpack.config.js文件,那么怎么打包
- 查看webpack历史版本
- 如何为webpack加一些命令行使用参数
- webpack-cli的作用是什么
- webpack.config.js mode
- 模块包括什么
- 加载某些模块需要哪些loader
- file-loader(转换图片的loader)
- url-loader( 像 file loader 一样工作,但如果文件小于限制,可以返回 base64图片)
- css-loader style-loader
- 为什么style-loader要写在css-loader前
- sass/less/stylus文件的loader
- postcss-loader结合autoprefixer
- importLoaders
- 模块化的css
- 如何使用webpack打包字体文件
- plugins
- html-webpack-plugin
- clean-webpack-plugin
- entry/output
- SourceMap
- 修改模块文件之后,webpack如何实现自动编译更新
- 使用webpack-dev-server为什么不生成dist目录了
- 热模块替换
- babel
- @babel/polyfill和@babel/plugin-transform-runtime区别与使用
- webpack配置react代码打包
- Tree Shaking
- Development 和 Production模式的区分打包
- webpack.dev.js
- webpack.prod.js
- 解决开发和生产模式下的配置文件大量重复代码问题
- 如何合并上述拆分
- webpack和code splitting
- SplitChunksPlugin
- lazy Loading懒加载
- 打包分析
- Prefetching/Preloading modules
- webpack-dev-server问题
- webpack如何对css文件进行代码分割
- webpack与浏览器缓存
- shimming(垫片)
- webpack 环境变量
- typescript的打包配置
- 使用webpackDevServer实现请求转发
- webpackDevServer解决单页面应用路由问题
- Eslint在webpack中的配置
- webpack性能提升
webpack核心
webpack核心是模块打包工具
搭建webpack项目
1、新建文件夹,进入
2、npm init //初始化npm
3、安装webpack(全局或者局部),这里局部安装
npm install webpack webpack-cli --save-dev
npm install webpack webpack-cli --g//全局安装
//不推荐全局安装webpack,因为全局安装之后如果多个webpack项目版本不一致,全局安装之后其他项目就不能再运行起来了,解决的办法就是先删除当前版本号,在安装对应版本webpack即可启动项目,
但是两个项目之间有依赖关系,又想启动webpack4.0又想启动webpack5.0项目,通过全局安装就没办法了
4、局部安装查看webpack信息可以使用
npx webpack -v 或者 webpack -v (npx 也适用于局部安装中查看其它插件信息)
5、初始化完成,之后就可以创建一些项目相关文件夹,如
src目录 //开发目录
dist目录 //存放打包后的文件
6、根目录下创建index.html文件,并且引入打包后的js文件,如引入bundle.js
7、src下创建一些js或者css
8、给项目创建一个webpack配置文件在项目根目录,webpack.config.js
搞定!
基本配置
const path = require('path');
module.exports = {
entry: './src/script/main.js',//打包入口,从哪个文件开始,必须是相对路径
output: {
path: path.resolve(__dirname + "/dist/js"), //打包后输出到的目录,必须是绝对路径// 必须是绝对路径(使用 Node.js 的 path 模块)
filename: "bundle.js", //打包后的文件名叫什么
},
}
//__dirname就是webpack所有当前目录的路径
//随后在项目根目录执行 webpack命令即完成打包工作
创建webpack.config.js的原因
如果直接使用webpack这个命令的话,webpack会直接在项目根目录去寻找webpack.config.js文件,它作为默认的配置去运行
webpack默认配置文件如果不叫webpack.config.js文件,那么怎么打包
使用--config 默认配置文件名,例如
webpack --config webpack.dev.config.js
即可完成打包
查看webpack历史版本
npm info webpack
当然也可以使用npm info 查看其它安装包历史版本信息
如何为webpack加一些命令行使用参数
1、可以配合npm的脚本做到
2、打包package.json
4、找到script属性
5、在这个属性里面定义一段脚本,脚本内容就是真是的webpack命令
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"webpack": "webpack --config webpack.config.js --progress --display-modules --display-reasons"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.2.0",
"webpack-cli": "^4.1.0"
}
}
"webpack(随意起名,中文除外)": "webpack --config webpack.config.js --progress --display-module --colors --displau-reason"
//比如使用--progress看到打包的过程,使用--display-modules看到打包的模块,--display-reasons打包原因
参见:https://www.webpackjs.com/api/cli/#%E5%B8%B8%E7%94%A8%E9%85%8D%E7%BD%AE
6、上面那段话就是webpack命令行配置
7、然后使用npm run webpack就执行以上命令了
webpack-cli的作用是什么
就是让开发者可以在命令行中webpack命令,假设不安装webpack-cli这个包,那么就没有办法在
命令行运行webpack或者npx webpack这样的指令,
webpack.config.js mode
If not set, webpack sets production as the default value for mode.
module.exports = {
mode: 'development',
entry: './src/js/main.js',
output: {
path: path.resolve(__dirname + '/dist/js'),
filename: "bundle.js"
}
}
模块包括什么
模块不止js,也还包括css,图片等等....
加载某些模块需要哪些loader
因为webpack默认只能打包js模块,loader 用于对模块的源代码进行转换,可以将文件从不同的语言(如 TypeScript)转换为 JavaScript
file-loader(转换图片的loader)
1、
module.exports = {
...,
module: {
rules: [
{
test: /\.(jpe?g|png|gif)$/,
use: [{loader: "file-loader"}]
}
]
}
}
2、上面打包之后图片打包出来的文件名是一个很长的字符串,如果想不改变图片的名字,如何做?
module: {
rules: [
{
test: /\.(jpe?g|png|gif)$/,
use: [{
loader: "file-loader",
options: {
name: '[name].[ext]'
}
}],
}
]
}
options: {
name: '[name]_[hash].[ext]' //资源的基本名称/内容的哈希值/资源扩展名称。。。
}
3、如何将图片打包后指定到特定文件夹
options: {
name: '[name]_[hash].[ext]',
outputPath: '../images/'
}
outputPath: '../images/' //指定打包到哪里的文件夹
4、常用整合
rules: [
{
test: /\.(jpe?g|png|gif)$/,
use: [{
loader: "file-loader",
options: {
name: '[name]_[hash].[ext]',
outputPath: '../images/'
}
}],
}
]
url-loader( 像 file loader 一样工作,但如果文件小于限制,可以返回 base64图片)
url-loader最佳使用方式是什么:
图片很小的时候使用url-loader将图片转换为data-url放到打包好的js中,减少了HTTP请求,但是如果图片过大,就要像file-loader一样将图片放到dist路径下,不要打包到压缩文件js文件中,因为这样可以让
压缩的js文件快速加载完成,页面可以快速显示出来,不然压缩的js会很大,加载它的时间很长,页面很久才能展示出来
如何实现以上说法?
module: {
rules: [
{
test: /\.(jpe?g|png|gif)$/,
use: [{
loader: "url-loader",
options: {
name: '[name]_[hash].[ext]',
outputPath: '../images/',
limit: 2048
}
}],
}
]
}
limit: 2048 //作用就是如果图片大小超过了2048字节的话,那么就会像file-loader一样打包到dist文件夹下生成一个图片,相反直接将图片变成base64字符串放到bundle.js中
css-loader style-loader
style-loader 将模块的导出作为样式添加到 DOM 中
css-loader 解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码
{
test: /\.css$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"}
],
}
打包后的css代码会到压缩后的js文件中
为什么style-loader要写在css-loader前
因为loader的加载顺序是从右往左,从下到上
sass/less/stylus文件的loader
sass-loader stylus-loader less-loader 具体看文档
{
test: /\.scss$/,
use: [{
loader: "style-loader" // 将 JS 字符串生成为 style 节点
}, {
loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
}, {
loader: "sass-loader" // 将 Sass 编译成 CSS
}]
}
postcss-loader结合autoprefixer
使用autoprefixer向CSS规则添加供应商前缀。
{
test: /\.scss$/,
use: [
{
loader: "style-loader" // 将 JS 字符串生成为 style 节点
},
{
loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
},
{
loader: "sass-loader" // 将 Sass 编译成 CSS
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
[
'autoprefixer',
{
// Options
},
],
],
},
},
}
]
}
还需在package.json文件上加入以下才生效:
"browserslist": [
"defaults",
"not ie < 11",
"last 2 versions",
"> 1%",
"iOS 7",
"last 3 iOS versions"
]
importLoaders
查询参数 importLoaders,用于配置「css-loader 作用于 @import 的资源之前」有多少个 loader。
{
loader: 'css-loader',
options: {
importLoaders: 1 // 0 => 无 loader(默认); 1 => postcss-loader; 2 => postcss-loader, sass-loader
}
},
模块化的css
避免全局样式污染
这样引入css文件
import styles from '../css/style.scss'
不再这样引入
import '../css/style.scss'
使用
style.样式名
配置modules:true
{
loader: "css-loader", // 将 CSS 转化成 CommonJS 模块
options: {
importLoaders: 0,
modules: true,
}
},
注意:css模块化还需要具体看一下
如何使用webpack打包字体文件
使用file-loader
{
test: /\.(eot|woff|ttf|svg)$/,
use: [{
loader: "file-loader"
}],
},
plugins
plugins 可以在webpack运行到某个时刻的时候,帮你做一些事情
html-webpack-plugin
作用:
会在打包结束后自动生成一个html文件,并把打包生成的js自动引入到这个html文件之中,它是在打包之后运行的
使用:
plugins: [
new HtmlWebpackPlugin()
]
===============================
也可以使用自定义HTML的模板,使用方式如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webpackDemo</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
plugins: [
new HtmlWebpackPlugin({
template: "./index.html"
})
]
以上方式模板里面也不需要手动引入打包生成的js,webpack会自动将它注入
clean-webpack-plugin
作用:实现重新打包dist目录先删除,然后在执行打包,实在打包之前运行的
它没有被收入官网
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
new CleanWebpackPlugin(),
默认不传参数时删除的文件是output=》path=》最后一级指定的文件夹,但是如果删除整个打包文件夹,可传递参数使用:
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [path.resolve(__dirname, './dist')] // 清除的文件/文件夹
}),
entry/output
如果多个入口文件可以像如下配置:
entry: {
main: './src/js/main.js',
sub: './src/js/main.js',
},
output: {
path: path.resolve(__dirname + '/dist/js'),
filename: "[name].js"
},
输出解析文件的目录,url 相对于 HTML 页面:
output: {
publicPath: "http://www.baidu.com",
},
SourceMap
SourceMap是为了解决开发代码与实际运行代码不一致时帮助我们debug到原始开发代码的技术。
开发模式时候默认开启source-map,生产模式没设置devtool的话自动是关闭source-map且设置为none,使用uglifyjs-webpack-plugin 要在里面设置sourcemap:true
mode: "production",
devtool: "cheap-module-source-map",
//production devtool: "cheap-module-source-map",
//development devtool: "eval-cheap-module-source-map",
如上配置,生产和开发使用不同的映射
其实sourcemap配置的关键字只有5个,eval(评估、描述)、source-map、cheap(便宜、廉价)、module、inline的任意组合,
这五个关键字每一项都代表一个特性,这四种特性可以任意组合。分表代表以下五种特性:
eval:使用eval包裹模块代码
source-map:产生.map文件
cheap:不包含列信息,也不包含loader的source-map
module:包含loader的source-map(如jsx to js,babel的sourcemap)
inline:将.map作为DataUrl嵌入,不单独生成.map文件(这个配置项比较少见)
修改模块文件之后,webpack如何实现自动编译更新
方法一:
在之前在package.json中设置启动项的地方增加--watch:
"dev": "webpack --config webpack.config.js --watch"
devServer: {
contentBase:'./dist/js',
},
随后重新命令行打包再修改文件就可以实现自动编译更新了,但是以上解决方案需要每次修改后自己刷新页面才会看到最新内容
方案二:
实现效果期望:第一次运行npm run dev就可以实现自动更新打包,自动打开浏览器且不需要手动刷新浏览器还可以开启http服务器可以发送ajax请求:
使用webpack-dev-server实现
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack --config webpack.config.js --watch",
"watch": "webpack-dev-server"
},
devServer: {
contentBase: path.join(__dirname, "dist/js"),
open: true, //自动打开浏览器并且指定端口号
port: 3000 //修改默认端口号
},
之后运行 npm run watch就可以实现以上效果了
注意:webpack5.2.0中"webpack-cli默认和webpack-dev-server不兼容,将webpack-cli版本修改为"webpack-cli": "^3.3.12"重新安装更新即可
使用webpack-dev-server为什么不生成dist目录了
webpack-dev-server状态下还是会对代码进行打包的,但是打包生成的文件并不会放在dist目录下了,而是放到了电脑的内存中了,这样可以有效提升打包速度,提升开发效率
热模块替换
devServer: {
contentBase: path.join(__dirname, "dist/js"),
open: true,
hot: true,//开启热模块替换
hotOnly: true,//启用不刷新页面的热模块替换(参见devServer.hot),作为构建失败时的回退。
},
babel
用于将 ES6+版本的代码转换为向后兼容的 JavaScript 语法
使用:
npm install --save-dev babel-loader @babel/core
module: {
rules: [
{ test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
]
}
....
具体查看官方文档:https://www.babeljs.cn/setup#installation
但是只使用babel是不够的,
Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。
举例来说,ES6在Array对象上新增了Array.from方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用babel-polyfill,为当前环境提供一个垫片。
import '@babel/polyfill'
...
参考自:https://www.jianshu.com/p/67dedc89b13d
但是使用babel-polyfill之后,它会将没有使用到的ES6+的语法转化也都打包到里面了,导致打包文件很大,如何处理呢?
{
"presets": [
[
"@babel/env",
{
"useBuiltIns": "usage"//设置这个就可以开启按需转义了,打包之后的文件也会很小,使用它的时候也不需要再在每个需要使用转义的文件定义引入import '@babel/polyfill'
}
]
]
}
@babel/polyfill和@babel/plugin-transform-runtime区别与使用
babel 在转译的过程中,对 syntax 的处理可能会使用到 helper 函数,对 api 的处理会引入 polyfill。
默认情况下,babel 在每个需要使用 helper 的地方都会定义一个 helper,导致最终的产物里有大量重复的 helper;引入 polyfill 时会直接修改全局变量及其原型,造成原型污染。
@babel/plugin-transform-runtime 的作用是将 helper 和 polyfill 都改为从一个统一的地方引入,并且引入的对象和全局变量是完全隔离的,这样解决了上面的两个问题。
通常:打包业务代码使用@babel/polyfill,打包库文件使用plugin-transform-runtime
webpack配置react代码打包
@babel/preset-react
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage"
}
],
[
"@babel/preset-react"
]
]
}
>https://babeljs.io/docs/en/babel-preset-react#docsNav
Tree Shaking
只打包引用的代码,没使用到的代码不被打包
如一个文件导出one、two两个方法,然后其他文件只使用了one方法,那如果不使用tree shaking的时候,one、two两个方法都会被打包进去,
但是如果使用了tree shaking,就会只打包使用了的one方法。
注意:tree shaking只支持es module的引入,其他像commonjs方式引入的模块不被支持,因为es6 模块是静态引入,而comonjs模块是动态引入,
而tree shaking只支持静态引入。
如何实现:
在webpack配置文件中新增optimization属性,然后赋值对象为以下属性:
optimization: {
usedExports: true
}
注意:生产模式下将自动开启tree shaking,开发环境需要自己设置,因此生产模式不需要设置以上
Development 和 Production模式的区分打包
分别写两套配置文件:如:
webpack.dev.js webpack.prod.js
然后在packag.json中指定:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
},
webpack.dev.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: "development",
devServer: {
contentBase: path.join(__dirname, "dist"),
open: true,
hot: true,
},
devtool: "eval-cheap-module-source-map",
entry: {
main: './src/js/main.js',
},
output: {
path: path.resolve(__dirname + '/dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.(jpe?g|png|gif)$/,
use: [{
loader: "url-loader",
options: {
name: '[name]_[hash].[ext]',
outputPath: '../images/',
limit: 2048
}
}],
},
{
test: /\.css$/,
use: [
{
loader: "style-loader" // 将 JS 字符串生成为 style 节点
},
{
loader: "css-loader", // 将 CSS 转化成 CommonJS 模块
}
]
},
{
test: /\.(eot|woff|ttf|svg)$/,
use: [{
loader: "file-loader"
}],
},
{test: /\.js$/, exclude: /node_modules/, loader: "babel-loader"},
]
},
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [path.resolve(__dirname, './dist')] // 清除的文件/文件夹
}),
new HtmlWebpackPlugin({
template: "./index.html"
}),
new webpack.HotModuleReplacementPlugin(),
],
optimization: {
usedExports: true
}
}
webpack.prod.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
const path = require('path');
module.exports = {
mode: "production",
devtool: "cheap-module-source-map",
entry: {
main: './src/js/main.js',
},
output: {
path: path.resolve(__dirname + '/build'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.(jpe?g|png|gif)$/,
use: [{
loader: "url-loader",
options: {
name: '[name]_[hash].[ext]',
outputPath: '../images/',
limit: 2048
}
}],
},
{
test: /\.css$/,
use: [
{
loader: "style-loader" // 将 JS 字符串生成为 style 节点
},
{
loader: "css-loader", // 将 CSS 转化成 CommonJS 模块
}
]
},
{
test: /\.(eot|woff|ttf|svg)$/,
use: [{
loader: "file-loader"
}],
},
{test: /\.js$/, exclude: /node_modules/, loader: "babel-loader"},
]
},
plugins: [
new HtmlWebpackPlugin({
template: "./index.html"
}),
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [path.resolve(__dirname, './build')] // 清除的文件/文件夹
})
]
}
解决开发和生产模式下的配置文件大量重复代码问题
新建webpack.common.js文件
将公用代码放置到这里:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
const path = require('path');
module.exports = {
entry: {
main: './src/js/main.js',
},
output: {
path: path.resolve(__dirname + '/build'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.(jpe?g|png|gif)$/,
use: [{
loader: "url-loader",
options: {
name: '[name]_[hash].[ext]',
outputPath: '../images/',
limit: 2048
}
}],
},
{
test: /\.css$/,
use: [
{
loader: "style-loader" // 将 JS 字符串生成为 style 节点
},
{
loader: "css-loader", // 将 CSS 转化成 CommonJS 模块
}
]
},
{
test: /\.(eot|woff|ttf|svg)$/,
use: [{
loader: "file-loader"
}],
},
{test: /\.js$/, exclude: /node_modules/, loader: "babel-loader"},
]
},
plugins: [
new HtmlWebpackPlugin({
template: "./index.html"
}),
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [path.resolve(__dirname, './build')] // 清除的文件/文件夹
})
]
}
pro剩下:
const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common');
const proConfig = {
mode: "production",
devtool: "cheap-module-source-map",
}
module.exports = merge(commonConfig, proConfig)
dev剩下:
const path = require('path');
const webpack = require('webpack');
const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common');
const devConfig = {
mode: "development",
devServer: {
contentBase: path.join(__dirname, "dist"),
open: true,
hot: true,
},
devtool: "eval-cheap-module-source-map",
plugins: [
new webpack.HotModuleReplacementPlugin(),
],
optimization: {
usedExports: true
}
}
module.exports = merge(commonConfig, devConfig)
如何合并上述拆分
使用webpack-merge
module.exports = merge(commonConfig, devConfig) ,上述粘贴代码已经实现
webpack和code splitting
什么是代码分割:
它可以让代码分割到不同的文件,代码分割和webpack无关,它是单独一个概念,用来提升整个项目的性能。
webpack中实现代码分割的方式:
方式一:
同步代码,只需要在webpack.common.js中做optimization的配置即可
optimization: {
usedExports: true,
splitChunks: {
// include all types of chunks
chunks: 'all' //这里配置
}
}
方式二:
异步代码分割:异步代码指的是import这种语法,动态导入的组件或者模块的代码,对于这种代码无需做任何配置,它会自动进行代码分割,放置到新的文件中。
SplitChunksPlugin
webpack 代码分割,底层使用了 SplitChunksPlugin 插件
lazy Loading懒加载
通过import异步加载模块实现懒加载,它是es中的概念;
懒加载好处:
可以让页面加载速度变快,如初始化页面时用不到lodash,那么只加载需要的模块就好了,lodash不会初始化就被载入,页面初始化渲染速度更快。
打包分析
https://webpack.js.org/guides/code-splitting/#bundle-analysis
webpack官网推荐的几个
其中,下面这个观看起来更直观
https://github.com/webpack-contrib/webpack-bundle-analyzer
Prefetching/Preloading modules
> https://webpack.js.org/guides/code-splitting/#prefetchingpreloading-modules
//...
import(/* webpackPrefetch: true */ 'LoginModal');
等待核心代码加载完成之后,空闲时间再去加载懒加载的资源,使用上述可以提升性能
webpack-dev-server问题
webpack可以自动打开浏览器,但是不能自动刷新页面
webpack如何对css文件进行代码分割
看文档
webpack与浏览器缓存
output: {
path: path.resolve(__dirname + '/build'),
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js'
},
使用contenthash,如果文件没改动那么打包之后的对应文件contenthash值是一样的,但是如果改动了,
打包之后的hash是不同的,浏览器看到不同文件名称就会重新请求,相同文件名称使用本地缓存。
shimming(垫片)
如果使用第三方比较老的插件,比如jquery,那么引入的时候还不想每个页面挨个导入,那样可以使用如下方式:
new webpack.ProvidePlugin({
$: 'jquery'
})
以上方式之后就可以页面中使用jquery
webpack 环境变量
webpack --env.NODE_ENV=local --env.production --progress
webpack.config.js
module.exports = env => {
// Use env.<YOUR VARIABLE> here:
console.log('NODE_ENV: ', env.NODE_ENV); // 'local'
console.log('Production: ', env.production); // true
......
,,,,,,
typescript的打包配置
https://github.com/TypeStrong/ts-loader
使用webpackDevServer实现请求转发
devServer.proxy
const data = axios.get('/react/api/header.json')
devServer: {
contentBase: path.join(__dirname, "dist"),
open: true,
hot: true,
proxy: {
'/react/api': 'http://www.dell-lee.com'
},//此处做代理
},
以上发送的请求路径就是:http://localhost:8082/react/api/header.json
但是实际上是:http://www.dell-lee.com/react/api/header.json
但是后端使用某个接口是测试接口之后名称会改变,那前端如何处理呢?
如上面 /react/api/header.json 中的header在测试中用的test,那么可以像下面这样写
proxy: {
'/react/api': {
target: 'http://www.dell-lee.com',
pathRewrite: {"^header.json": "demo.json"}
}
},
以上发送的请求路径就是:http://localhost:8085/react/api/demo.json
但是实际上是:http://www.dell-lee.com/react/api/header.json
以上配置只是开发时候设置的转发,生产环境没设置dev-server
webpackDevServer解决单页面应用路由问题
<BrowserRouter>
<Route path='/' exact component={Home}/>
<Route path='/list' exact component={List}/>
</BrowserRouter>
但是上面只能匹配根目录,list匹配报错:Cannot GET /list
如何解决:
https://www.webpackjs.com/configuration/dev-server/#devserver-historyapifallback
proxy: {
'/react/api': {
target: 'http://www.dell-lee.com',
pathRewrite: {"header.json": "demo.json"}
}
},
historyApiFallback: true, //这块设置即可
Eslint在webpack中的配置
https://eslint.org/docs/user-guide/getting-started https://github.com/webpack-contrib/eslint-loader
代码检查与修复工具
配置eslint有两种方式,一种是在编辑器中直接配置,另一种在代码中配置
代码中配置方式:
eslint和eslint-loader结合使用
webpack性能提升
提升webpack打包速度的方法:
1、技术的更新迭代(node/npm/yarn)
2、尽可能少的模块上应用loader
比如babel-loader
{
test: /\.js$/,
exclude: /node_modules/,//抛除安装包下的或者使用include,只对include匹配的转换
loader: "babel-loader"
},
就是合理的使用exclude或者include可以降低loader执行频率,提升打包速度
3、尽可能少的使用plugin,并且确保plugin的可靠性
(1)比如对css进行代码压缩只是在生产版本配置,开发版本不配置,从而节约开发时每次打包时间
(2)另外一般使用的plugin都是webpack官方提供的,因为这些插件的性能经过官方测试是比较快的,
平时个人写的插件可能会解决打包时候的问题,但是这些插件的性能没法保证,因此最好使用官方推荐的插件
4、resolve参数合理配置
module.exports = {
entry: {
main: './src/js/main.js',
},
resolve: {
extensions: ['.js', '.jsx'],//导入文件可以省略这两个扩展名,然后自动先查找.js文件在查找.jsx文件
},
但是上述这样是合理的,不过如果在上述配置项中配置很多内容,那么每次都会进行很多文件查找,每次文件查找都会掉一次node底层这种操作,
会有性能损耗,因此只有引入js或者jsx这种逻辑文件的时候才会省略扩展名配置在这里,css和图片扩展名都不建议配置在这里
也可以给它添加别名:
resolve: {
extensions: ['.js', '.jsx'],
alias: {
assets: path.resolve(__dirname, 'src/assets')
}
},
5、控制包文件大小
1、使用Tree Shaking只打包使用的代码
2、使用splitChunks代码拆分
3、合理使用source-map,不同环境打包使用不同source-map
4、结合status分析打包结果