1. 前言
前段时间突发奇想,平时不是使用cra搭建项目就是使用其他三方模板, 都是基本上帮你配置好了所有的配置项,你只需要写业务代码就好了。但是回看一堆配置项时有时懵逼的,所以就想手动从0开始一步一步搭建一个基于webpack5的React Ts项目,以便于知道那些配置项是必须项,以及必须项都是为了完成什么任务,于是就有了下面的实践。
2. 初始化项目
项目目录结构就不多述了,对应的文件夹及文件无非就是 mkdir、touch的过程也不多说;
项目根路径下:
npm init -y
初始化简单的package.json配置文件
3. 初始化typeScript配置
yarn add typescript ts-loader --dev
关于--dev也无需多说,并且我的理解ts、ts-loader 均是服务项目,对于前端项目来说浏览器只需要js,所以为了生成js文件的其他的配置项均是服务项目应该放在devDependencies下。
可以全局安装ts
yarn add typescript global
然后项目根路径下:初始化ts配置项 tsconfig.json
tsc --init
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es6",
"target": "es5",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true
}
}
4.配置webpack相关
yarn add webpack webpack-cli webpack-merge html-webpack-plugin clean-webpack-plugin --dev
项目基本上都是分为开发环境和生产环境的,所以对于webpack的配置,个人新建了三个文件来存放不同的配置。
新建config 文件来存放webpack的配置文件:
-
webpack.base.js存放webpack的基本配置 -
webpack.dev.js存放webpack的开发环境配置 -
webpack.prod.js存放webpack的生产环境配置// config/webpack.base.js
const path = require('path') const { CleanWebpackPlugin } = require('clean-webpack-plugin') const HtmlWebpackPlugin = require('html-webpack-plugin') /**
- @type {import('webpack').Configuration} */
module.exports = { entry: { app: './src/index.tsx', }, output: { path: path.resolve(__dirname, '../dist'), filename: '[name].[hash].js', }, resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx'], }, plugins: [ new HtmlWebpackPlugin({ title: '管理后台', template: path.resolve(__dirname, '../index.html'), filename: 'index.html', }), new CleanWebpackPlugin(), ], }
合并配置项
由于我们是分文件配置webpack,所以就会存在合并配置项这个操作。上面安装的webpack-merge 就是实现这个功能的插件。
// config/webpack.dev.js
const webpackMerge = require('webpack-merge')
const baseConfig = require('./webpack.config.base')
const path = require('path')
/**
* @type {import('webpack').WebpackOptionsNormalized}
*/
const devServer = {
hot: true, port: 3000, host: '127.0.0.1', compress: true, open: true, proxy: { '/api': { target: 'http://localhost:8000', pathRewrite: { '^/api': '' }, secure: false } }}
const devConfig = {
mode: 'development',
devServer: devServer,
}
module.exports = webpackMerge.merge(baseConfig, devConfig)
// config/webpack.prod.js
const webpackMerge = require('webpack-merge')
const baseConfig = require('./webpack.config.base')
/**
* @type {import('webpack').WebpackOptionsNormalized}
*/
const prodConfig = {
mode: 'production',
}
module.exports = webpackMerge.merge(baseConfig, prodConfig)
5. 配置babel
yarn add babel-loader babel-plugin-import @babel/cli @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript --dev
在根目录新建.babelrc 文件
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
webpack.base.js中添加mode配置
module.exports = {
...
module: {
rules: [
{ test: /\.(js|jsx)$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.(ts|tsx)$/, loader: 'ts-loader', exclude: /node_modules/ },
],
},
};
6. 配置React
yarn add react react-dom react-router-dom
yarn add @types/react @types/react-dom @types/react-router-dom --dev
新建html文件
根目录新建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>
<%= htmlWebpackPlugin.options.title %>
</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
新建工程入口文件
新建src 目录下新建App.tsx index.tsx
// App.tsx
import React from 'react'
const App = () => {
return <div>1234</div>
}
export default App
// index.tsx
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))
7. 功能性配置
yarn add style-loader less-loader less css-loader postcss-loader postcss-normalize autoprefixer postcss-preset-env --dev
因为我们平时开发中不只是使用less,也会使用到scss module,所以同时配置一下,安装依赖
yarn add react-dev-utils resolve-url-loader --dev
webpack.base.js中添加mode配置,
这里后续我移除了sass,使用less,sass的依赖包安装总是失败
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent')
module.exports = {
...
module: {
rules: [
...
{
test: /\.(css|less)$/, exclude: /\.module\.scss$/, use: [isDev ? require.resolve('style-loader') : MiniCssExtractPlugin.loader,
'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { plugins: [ require('postcss-preset-env')() ], }, } }, "less-loader"] },
{
test: /\.module\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
getLocalIdent: getCSSModuleLocalIdent,
},
},
},
'postcss-loader',
'sass-loader',
],
},
],
},
};
图片地址解析
webpack5 内置 assets 类型,我们不需要额外安装插件就可以进行图片等资源文件的解析,配置如下:
{
test: /\.(jpe?g|png|gif|svg|woff|woff2|eot|ttf|otf)$/i,
type: "asset/resource",
},
8. 性能优化
webpack5 引入了缓存来提高二次构建速度,我们只需要在 webpack 配置文件中加入如下代码即可开心缓存
cache: {
type: 'filesystem',
// 可选配置
buildDependencies: {
config: [__filename], // 当构建依赖的config文件(通过 require 依赖)内容发生变化时,缓存失效
},
name: 'development-cache',
},
9. 完整配置
webpack.base.js
// webpack.base.js
const path = require('path')const HtmlWebpackPlugin = require('html-webpack-plugin')const { CleanWebpackPlugin } = require('clean-webpack-plugin')const MiniCssExtractPlugin = require('mini-css-extract-plugin')/** * @type {import('webpack').Configuration} */const isDev = process.env.NODE_ENV === 'development'module.exports = { target: 'web', entry: { app: './src/index.tsx', }, output: { path: path.resolve(__dirname, '../dist'), filename: '[name].[hash].js', }, module: { rules: [ { test: /\.(js|jsx)$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.(ts|tsx)$/, loader: 'ts-loader', exclude: /node_modules/ }, { test: /\.(css|less)$/, exclude: /\.module\.scss$/, use: [isDev ? require.resolve('style-loader') : MiniCssExtractPlugin.loader, 'css-loader', { loader: 'postcss-loader', options: { postcssOptions: { plugins: [ require('postcss-preset-env')() ], }, } }, "less-loader"], }, { test: /\.(jpe?g|png|gif|svg|woff|woff2|eot|ttf|otf)$/i, type: 'asset/resource', }, ], }, resolve: { extensions: ['.tsx', '.ts', '.js', '.jsx'], }, plugins: [ new HtmlWebpackPlugin({ title: '管理后台', template: path.resolve(__dirname, '../public/index.html'), filename: 'index.html', }), new CleanWebpackPlugin(), new MiniCssExtractPlugin({ filename: 'css/[name].[hash].css', }) ], cache: { type: 'filesystem', // 可选配置 buildDependencies: { config: [__filename], // 当构建依赖的config文件(通过 require 依赖)内容发生变化时,缓存失效 }, name: 'development-cache', },}
webpack.dev.js
HotModuleReplacementPlugin 这个是热更新,
const webpackMerge = require('webpack-merge')const baseConfig = require('./webpack.base')const webpack = require('webpack');//引入webpack // const path = require('path')/** * @type {import('webpack').WebpackOptionsNormalized} */const devServer = { hot: true, port: 3000, host: '127.0.0.1', compress: true, open: true, proxy: { '/api': { target: 'http://localhost:8000', pathRewrite: { '^/api': '' }, secure: false } }}const devConfig = { mode: 'development', devServer: devServer, plugins: [//配置插件的节点 new webpack.HotModuleReplacementPlugin() //new 一个热更新的模块对象 ]}module.exports = webpackMerge.merge(baseConfig, devConfig)
webpack.prod.js
const webpackMerge = require('webpack-merge')
const baseConfig = require('./webpack.config.base')
/**
* @type {import('webpack').WebpackOptionsNormalized}
*/
const prodConfig = {
mode: 'production',
}
module.exports = webpackMerge.merge(baseConfig, prodConfig)
webpack 配置项很多,功能也是很强大,我目前只是基本的的一个可用项目搭建,后续还会随着学习过程逐步补充
10. css提取成单独的打包文件
上述配置中的css是打包到js中的,所以如果想要把css单独打包出来,就需要做一下配置,安装依赖
yarn add mini-css-extract-plugin --dev
修改webpack.base.js 中的配置
module.exports = {
...
plugins: [new MiniCssExtractPlugin({
filename: 'css/[name].[hash].css',
})],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
}
11. 配置开发服务器
安装依赖
yarn add webpack-dev-server --dev
package.json 中添加启动命令
"scripts": {
"start": "webpack serve --open --config ./config/webpack.dev.js --mode=development", "build": "webpack --config ./config/webpack.prod.js --mode=production"
},
当完成上述的步骤的时候,当你运行的时候,可能会收到这么一个报错。
因为是ts的项目,所以这个时候需要进行声明文件的书写。
新建declaration.d.ts
declare module '*.scss' { const content: Record<string, string>
export default content
}
12.获取良好的css 代码提示
需要使用到一个插件
yarn add typescript-plugin-css-modules --dev
配置tsconfig.json
{
"compilerOptions":
{
"plugins": [{ "name": "typescript-plugin-css-modules" }]
}
}
这样,一个基本的项目后就已经搭建成了,当然想全部搞懂确实也需要下功夫。