从0开始搭建一个自己的react-app脚手架(webpack5+typescript)
1、前置工作
mkdir react-cli
cd react-cli
npm init --yes
此教程都是以yarn安装依赖的,npm、cnpm也可
平时我们可能自己写项目不常用eslint,、prettier等,在公司项目里这些也是很重要的,毕竟多人开发涉及到规范问题嘛,所以我们就先来配置eslint、prettier。
2、prettier eslint配置
yarn add prettier eslint -D
新建一个.prettierrc文件
具体怎么配置的其实有很多中参数,可以去官网或者网上自己看看,我这边就只列出一点吧。
{
"trailingComma": "none",//属性末尾不添加','
"tabWidth": 2, //缩进大小
"semi": true,//是否添加分号
"singleQuote": false, //是否单引号
"endOfLine": "lf", //末尾留行
"jsxSingleQuote": false, //jsx内属性是否单引号
"printWidth": 120,
"bracketSpacing": true, //在对象中个属性之间打印空格
"arrowParens": "always"
}
这个配置文件有什么用呢,其实就是结合我们的vscode插件来进行保存时自动格式化,首先要安装插件Prettier哈,然后在文件下新建.vscode文件夹,在下面新建settings.json
{
"search.exclude": {
"**/node_modules": true,
"dist": true,
"yarn.lock": true
},
"editor.formatOnSave": true,
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[less]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
这样别人下你的脚手架就可以用你的配置了。到这你的prettier就配置完成啦
接下来我们配置eslint
npx eslint --init
执行npx eslint的时候会有选择让你一键生成配置文件很方便,我们就来看看各个问题吧。
- 1、how would you like to use Eslint?
我们选择第三条check syntax,find problem,and enforce code style - 2、What type of modules does your project use
JavaScript modules (import/export)使用esmodule - 3、Which framework does your project use?
果断react啊 - 4、Does your project use TypeScript?
果断ts - 5、Where does your code run?
brower、node都要,因为我们还会使用到node中的模块. - 6、How would you like to define a style for your project?
这个就选择use a popular style guide 受欢迎肯定不会错的啦,跟着大家走 - 7、Which style guide do you want to follow?
airbnb 不多说,大家都用它 - What format do you want your config file to be in?
这个就随便啦js,json,yaml差不多,这边我就选择js了
选完后,他会根据我们选择的配置安装依赖
初始化完成后我们的eslint.js就是这样子的啦
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
'plugin:react/recommended',
'airbnb',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
sourceType: 'module',
},
plugins: [
'react',
'@typescript-eslint',
],
rules: {
},
};
这些配置还不够,我们还需要进行一些配置
extends: [
"plugin:react/recommended",
"plugin:eslint-plugin-react/recommended",
"plugin:@typescript-eslint/recommended",
"airbnb",
"airbnb/hooks",
],
plugins: ["react", "unicorn", "@typescript-eslint",],
settings: {
"import/resolver": {
node: {
extensions: [".tsx", ".ts", ".js", ".json"] //import index from './index'自动推导后缀
},
typescript: {}
}
}
当然还要配置我们的ruls,这其实配置不好就会很难受,很容易跟prettier发生冲突。我这边是这么配置的哈,其实配置这个的时候我也踩了不少坑。。都是一步一步走过来的。才的坑多了就有经验了。
"import/extensions": [
ERROR,
"ignorePackages",
{
ts: "never",
tsx: "never",
json: "never",
js: "never"
}
],
"no-var": "error",
"no-use-before-define": "off",
"@typescript-eslint/explicit-module-boundary-types": 0,
"react/jsx-filename-extension": [1, { extensions: [".tsx", ".ts"] }],
"unicorn/prevent-abbreviations": "off",
"comma-dangle": ["error", "never"],
"import/no-unresolved": "error",
"space-in-parens": "off",
"spaced-comment": "off",
"eol-last": "off",
quotes: [0, "double"],
semi: [2, "always"]
好了之后我这边的eslintrc.js就是这样子的啦
module.exports = {
env: {
browser: true,
es2021: true,
node: true
},
extends: [
"plugin:react/recommended",
"airbnb",
"plugin:@typescript-eslint/recommended",
"airbnb/hooks",
"plugin:eslint-plugin-react/recommended"
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaFeatures: {
jsx: true
},
ecmaVersion: 12,
sourceType: "module"
},
settings: {
"import/resolver": {
node: {
extensions: [".tsx", ".ts", ".js", ".json"]
}
}
},
plugins: ["react", "@typescript-eslint"],
rules: {
"no-var": "error",
"no-use-before-define": "off",
"@typescript-eslint/explicit-module-boundary-types": 0,
"react/jsx-filename-extension": [1, { extensions: [".tsx", ".ts"] }],
"unicorn/prevent-abbreviations": "off",
"comma-dangle": ["error", "never"],
"import/no-unresolved": "error",
"space-in-parens": "off",
"spaced-comment": "off",
"eol-last": "off",
quotes: [0, "double"],
semi: [2, "always"]
}
};
我们可以新建一个index.ts文件,然后我们可以随便写一点比如我们rules中有no-var就说明我们不能用var来声明变量,但是我们发现eslint中并没有报错,这是啥原因呢,害,其实很简单,重启一下试试?这边踩坑有点多我也记不得了哈哈,然后在安装个vscode的eslint插件,这样就有fix功能啦。eslint还可以使用命令行来进行检测,编写npm script,因为默认不检测tsx所以我们通过–ext来设置检测哪些后缀
"lint": "npm run lint-eslint",
"lint-eslint": "npx eslint src --ext .js,.ts,tsx",
接下来执行下yarn lint试下?eslint的配置就将讲到这里啦
3、webpack
上面说的都是补充内容,其实不配置问题也不大,自己用完全不用配置但是嘛规范还是要从小抓起的啦。话不多说开始我们的webpack配置,没有了解过的最好去了解一下webpack的基本使用。最基本的entry,output,loader,plugin懂了就可以啦。
yarn add webpack webpack-cli -D
新建一个src文件夹和一个build文件夹,src下就是平常我们写逻辑的啦,build文件下我们会写一些webpack的配置。
我们这边先新建一个webpack.config.js,这边会有个坑哈,我们因为选的是esmodule所以eslint会对commonjs报错,怎么解决呢,很简单配置个.eslingignore就行啦。webpack.config.js这里配置如下
const { ROOT_PATH } = require("../constant");
const path = require("path");
module.exports = {
target: "web",
entry: {
app: path.resolve(ROOT_PATH, "./src/index.js")
},
output: {
filename: `js/[name]:[hash:8].js`,
path: path.resolve(ROOT_PATH, "./dist")
}
};
这边还有一个constant文件,也是个基础配置文件,我直接新建在build下面了,内容如下
const path = require("path");
const ROOT_PATH = path.resolve(__dirname, "../");
module.exports = { ROOT_PATH };//ROOT_PATH就是我们的项目根目录啦
然后我们就开始我们的第一次打包,从配置文件可以看出我们的入口文件是src下的index
.js所以我们在src下新建一个index.js然后随便写点js就行啦,接下来在package.json下面写script
"dev": "webpack --config ./build/config/webpack.config.js"
然后执行yarn dev试试我们就可以看到在根目录下产生了dist文件夹啦里面就有我们打包好的内容。
我们平时的环境至少都有两个,开发和生产环境吧这两个环境的配置有些相同又有些不同,所以我们就可以对其进行一些简单的封装,我们将webpack.config.js改成webpack.common.js来把它当作各个环境下的共同部分,然后在新建两个webpack.dev.js和webpack.prod.js来表示不同环境下的不同配置,然后根据不同的文件加载不同的配置文件即可,但是公共部分怎么加载呢,这里我们就需要使用webpack-merge了
yarn add webpack-merge -D
然后分别配置我们的两个配置文件吧
//webpack.dev.js
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
module.exports = merge(common, {
mode: "development"
});
//webpack.prod.js
const { merge } = require("webpack-merge");
const common = require("./webpack.common");
module.exports = merge(common, {
mode: "production"
});
环境怎么区分呢?用过vuecli的可能会看到过一个变量叫做process.env.NODE_ENV,这是node的一个环境变量,NODE_ENV其实就是我们自己声明的区分不同环境的变量了,但是不同平台的声明方式不同,所以我们这里就又要使用了cross-env,他可以根据不同环境来声明我们的NODE_ENV,具体怎么做嘞,来看看
yarn add cross-env -D
修改我们的webpack.common.js
const { ROOT_PATH } = require("../constant");
const path = require("path");
const isDevelopment = process.env.NODE_ENV === "development" ? true : false;
module.exports = {
target: "web",
entry: {
app: path.resolve(ROOT_PATH, "./src/index.ts")
},
output: {
filename: `js/[name]${isDevelopment ? "" : ".[hash:8]"}.js`,
path: path.resolve(ROOT_PATH, "./dist")
}
};
上面做的操作就是如果是开发环境就不在打包文件后面添加哈希值,生产环境则添加。
然后重新写我们的npm script
"dev": "cross-env NODE_ENV=development webpack --config ./build/config/webpack.dev.js",
"build": "cross-env NODE_ENV=production webpack --config ./build/config/webpack.prod.js",
分别执行yarn dev、yarn build就可以看到区别啦。
我们可以发现每次打包之前的打包内容都还没清楚,这时候就需要我们的plugin了,这里我们使用clean-webpack-plugin插件
yarn add clean-webpack-plugin -D
修改webpack.common.js
const { ROOT_PATH } = require("../constant");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const path = require("path");
const isDevelopment = process.env.NODE_ENV === "development" ? true : false;
module.exports = {
target: "web",
entry: {
app: path.resolve(ROOT_PATH, "./src/index.ts")
},
output: {
filename: `js/[name]${isDevelopment ? "" : ".[hash:8]"}.js`,
path: path.resolve(ROOT_PATH, "./dist")
},
plugins: [new CleanWebpackPlugin()]
};
这下再次打包我们就会发现之前的打包内容都被清除啦。
之前用过vue-cli的肯定知道我们还会有个index.html,打包后的文件中有index.html,还会引入我们打包后的js,再一步还会在本地起一个server,这又是怎么实现的呢,一步一步来,首先我们在目录下见一个public目录下,这个文件下我们有一个index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>react-cli</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
我们写一个div并给一个id为app,为什么要这么做呢,熟悉vue或者react的肯定知道吧,这是我们挂载的根节点呀。怎么打包进dist呢?这时候就需要另一个插件啦,叫html-webpack-plugin
yarn add html-webpack-plugin -D
修改webpack.common.js
const { ROOT_PATH } = require("../constant");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
const isDevelopment = process.env.NODE_ENV === "development" ? true : false;
module.exports = {
target: "web",
entry: {
app: path.resolve(ROOT_PATH, "./src/index.js")
},
output: {
filename: `js/[name]${isDevelopment ? "" : ".[hash:8]"}.js`,
path: path.resolve(ROOT_PATH, "./dist")
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(PROJECT_PATH, "./public/index.html"),
filename: "index.html",
cache: false //关闭缓存
})
]
};
修改index.js
const dom = document.querySelector("#app");
dom.innerHTML = "hello,react";
这时候我们在执行一下yarn dev,就可以看到dist下有index.html,而且还引入了我们打包出来的js,如果你可以本地preview,就可以看到我们js执行的效果啦。
接下来就是在本地启服务啦,这里我们需要用到webpack的devserver了,
yarn add webpack-devserver -D
因为只有开发环境下需要启服务,所以我们就直接在webpack.dev.js下进行修改,很简单
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
const path = require("path");
const { ROOT_PATH } = require("../constant");
module.exports = merge(common, {
mode: "development",
devServer: {
overlay: true, //编译错误直接显示在页面上
contentBase: path.resolve(ROOT_PATH, "./dist"),
port: "3000", // 指定端口,默认是8080
compress: true, // 是否启用 gzip 压缩
open: true, // 打开默认浏览器
hot: true // 热更新
}
});
然后在修改我们的npm scripts
"dev": "cross-env NODE_ENV=development webpack serve --config ./build/config/webpack.dev.js",
在执行yarn dev就可以啦,我们打开3030端口就可以看到页面啦
4、处理各种类型的文件
我们都知道webpack是将各个文件都当作一个模块的,默认是只能处理文件的,如果要处理如图片、css等文件就需要我们的loader啦
yarn add file-loader url-loader css-loader less-loader style-loader -D
file-loader和url-loader是处理图片等文件的,他可以将图片打包成静态文件,也可以打包成js文件,url-loader是基于file-loader的哈。接下来就配置我们的loader啦
const { ROOT_PATH } = require("../constant");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
const isDevelopment = process.env.NODE_ENV === "development" ? true : false;
module.exports = {
target: "web",
entry: {
app: path.resolve(ROOT_PATH, "./src/index.js")
},
output: {
filename: `js/[name]${isDevelopment ? "" : ".[hash:8]"}.js`,
path: path.resolve(ROOT_PATH, "./dist")
},
module: {
rules: [
{
test: /.css$/,
use: ["style-loader", "css-loader"]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(ROOT_PATH, "./public/index.html"),
filename: "index.html",
cache: false
})
]
};
loader的配置就如上图,其中use是一个数组,里面的执行的从后往前一次执行,所以一定要注意顺序哈!!对于css的处理我们就是css-style先执行,在执行style-loader。当然数组项可以是一个对象比如css-loader你也可以写成
rules: [
{
test: /.css$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: false,
sourceMap: false
}
}
]
}
]
我们可以在src下写个index.css,然后在index.js中import
//index.css
#app {
color: red;
}
// index.js
import "./index.css";
const dom = document.querySelector("#app");
dom.innerHTML = "hello,react";
在执行yarn dev就能看到css效果啦,less也一样啦,配置loader即可,如果配置项不清楚可以查看文档哟。
对于图片文件我们也是一样处理的,使用的loader是file-loader和url-loader配置如下
{
test: [/\.jpg$/, /\.png$/, /\.gif$/],
use: [
{
loader: "url-loader",
options: {
limit: 1024,
name: "[name].[contenthash:8].[ext]",
outputPath: "assets/images"
}
}
]
},
上面url-loader的配置项意思是低于1024kb的就打包进入js文件里,否则保存在assets/images目录下
5、编译ts
浏览器是识别不了ts的啦,webpack自然也不行,毕竟他本来就是打包js的。所以我们就需要使用另一个神器 babel啦,话不多说先安装
yarn add @babel/core @babel/preset-env @babel/preset-typescript babel-loader -D
babel/core是babel的核心模块,babel/preset-env是用于降级js,因为部分浏览器还不支持es6语法就需要统一降为es5 ,babel/preset-typescript让ts编译成js的啦。 在本目录下建立配置文件.babelrc
{
"presets": ["@babel/preset-env", "@babel/preset-typescript"]
}
然后就可以配置loader啦,对ts、js、tsx等文件我们就都可以使用babel-loader来进行编译啦,配置跟上面的css一样
{
test: [/\.tsx$/, /\.js$/,/\.ts$/],
exclude: /node_modules/, //不编译node_modules模块内里
use: [
{
loader: "babel-loader",
options: {
cacheDirectory: true
}
}
]
}
6、tsconfig.json
我们在用ts的时候经常会看到tsconfig.json文件,这个文件的作用呢,就是定义一些编译选项,指定编译文件,执行下面步骤就可以看到配置文件啦
npx tsc --init
这边放出部分配置
"compilerOptions": {
"jsx":"react",
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs",
"strict": true,
"moduleResolution": "node", // 指定模块解析策略
"esModuleInterop": true, // 支持 CommonJS 和 ES 模块之间的互操作性
"resolveJsonModule": true, // 支持导入 json 模块
"baseUrl": "./", // 根路径
"paths": { // 路径映射,与 baseUrl 关联
"@/*": ["src/*"]
},
"forceConsistentCasingInFileNames": true, // 禁止对同一个文件的不一致的引用
"skipLibCheck": true, // 忽略所有的声明文件( *.d.ts)的类型检查
"allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入
"noEmit": true
},
"exclude": ["node_modules"],
主要就是我们的paths路径讲解,我们写过vue的肯定知道脚手架中@代表的是src目录,所以我们这边也可以配置映射路径,当然这样子配置只能保证ts文件不报错,但是真正的映射还得是在webpack中配置
在webpack.common.js下配置
const { ROOT_PATH } = require("../constant");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
const { resolve } = require("path");
const isDevelopment = process.env.NODE_ENV === "development" ? true : false;
module.exports = {
target: "web",
entry: {
app: path.resolve(ROOT_PATH, "./src/index.ts")
},
output: {
filename: `js/[name]${isDevelopment ? "" : ".[hash:8]"}.js`,
path: path.resolve(ROOT_PATH, "./dist")
},
resolve: {
extensions: [".tsx", ".ts", ".js", ".json"],
alias: {
"@": resolve(ROOT_PATH, "./src")
}
},
module: {
rules: [
{
test: /.css$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: false,
sourceMap: false
}
}
]
},
{
test: [/\.js$/, /\.ts$/],
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
cacheDirectory: true
}
}
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(ROOT_PATH, "./public/index.html"),
filename: "index.html",
cache: false
})
]
};
当我们这样配置后发现eslint还是会报错,这时候我们就需要使用eslint-import-resolver-typescript
npm install eslint-import-resolver-typescript -D
在eslint配置文件中配置
settings: {
"import/resolver": {
node: {
extensions: [".tsx", ".ts", ".js", ".json"]
},
typescript: {}
}
}
这样就可以啦.
7、React,React-dom配置
react核心两个包先安起来吧。
yarn add react react-dom
yarn add @babel/preset-react -D
babel/preset-react是用来转换react语法的哈配置仍旧在babelrc里
{
"presets": ["@babel/preset-env","@babel/react", "@babel/preset-typescript"]
}
在写react语法之前我们要先将它的ts声明文件下载下来。
yarn add @types/react @types/react-dom -D
好了接下来就可以开始我们的react书写啦
我们现在src下新建一个index.tsx,App.tsx index.tsx这就是我们的入口文件啦,App.tsx就可以是我们的外层容器组件啦
App.tsx里就是我们熟悉的React语法啦
import React from "react";
const App = () => <div>hello React</div>;
export default App;
index.tsx则是我们挂载dom
import React from "react";
import ReactDom from "react-dom";
import App from "@/App";
ReactDom.render(<App />, document.querySelector("#app"));
是不是很熟悉,就是我们的react官方脚手架里的内容啦。我们自己搭的用法当然一样啦
接下来干啥呢,当然是修改我们的入口文件改为index.tsx啦,改好之后我们再yarn dev看下,发现报了个错没有loader处理tsx的错误,我们去配置文件里看下原来是忘记配置tsx了,加上就行啦,下面附上完整的webpack.common.js
const { ROOT_PATH } = require("../constant");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
const { resolve } = require("path");
const isDevelopment = process.env.NODE_ENV === "development" ? true : false;
module.exports = {
target: "web",
entry: {
app: path.resolve(ROOT_PATH, "./src/index.tsx")
},
output: {
filename: `js/[name]${isDevelopment ? "" : ".[hash:8]"}.js`,
path: path.resolve(ROOT_PATH, "./dist")
},
resolve: {
extensions: [".tsx", ".ts", ".js", ".json"],
alias: {
"@": resolve(ROOT_PATH, "./src")
}
},
module: {
rules: [
{
test: /.css$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
modules: false,
sourceMap: false
}
}
]
},
{
test: [/\.js$/, /\.ts$/, /\.tsx$/],
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
cacheDirectory: true
}
}
]
},
{
test: [/\.png$/, /\.jpg$/, /\.jpeg$/, /\.gif$/, /\.svg$/],
use: ["url-loader"]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(ROOT_PATH, "./public/index.html"),
filename: "index.html",
cache: false
})
]
};
好了,现在脚手架的基本实现就到这里啦。
8、补充
图片处理
上面讲file-loader,url-loader的时候忘记给例子了,这边我们就来给个例子,修改App.tsx
import React from "react";
import img from "@/1.png";
const App = () => <img src="./1.png" alt="" />;
export default App;
我们发现ts报错了,找不到png的类型声明,简言之图片也是模块,但找不到他的类型,这时候ts的声明文件就体现作用啦,我们在src下新建一个types文件夹,这里面就放我们的声明文件啦,新建index.d.ts,声明一下就可以啦
declare module "*.svg";
declare module "*.png";
declare module "*.jpg";
declare module "*.jpeg";
declare module "*.gif";
declare module "*.bmp";
declare module "*.tiff";
在执行yarn dev试试呀
编译的时候进行ts校验
执行上面的步骤后,你可以尝试故意写错一些ts的语法,你会发现ts明明报错了,但是webpack却还是正常编译了,这是咋回事,因为我们编译的时候呀是不进行ts语法校验的,这时候就可以使用另一个插件fork-ts-checker-webpack-plugin
yarn add fork-ts-checker-webpack-plugin -D
用法和之前插件一样引入后直接new实例就行啦
添加进度条
添加进度条需要我们使用webpackbar插件
yarn add webpackbar -D
new WebpackBar({
name: isDevelopment ? "RUNNING" : "BUILDING",
color: "#52c41a"
})
终端只显示错误
我们现在yarn dev的时候还会现实编译问价内容,我们不需要显示,只需要现实错误就行啦,这里就需要在我们的dev-server下配置就行啦
devServer: {
stats: "errors-only", //只显示错误
overlay: true, //编译错误直接显示在页面上
contentBase: path.resolve(ROOT_PATH, "./dist"),
port: "3000", // 指定端口,默认是8080
compress: true, // 是否启用 gzip 压缩
open: true, // 打开默认浏览器
hot: true // 热更新
}
错误显示在页面
我们的错误可以通过error-overlay-webpack-plugin插件直接显示在页面上,具体可以去github查看下效果,用法很简单,github上写的也很清楚
到这里我们的整个搭建过程就结束啦,有问题的可以+qq 547783781询问哦
仓库地址