React脚手架配置
新建config/webpack.dev.js config/webpack.prod.js
安装依赖
npm i webpack-dev-server webpack webpack-cli -D
npm i eslint-webpack-plugin html-webpack-plugin style-loader css-loader postcss-loader
postcss-preset-env less-loader sass-loader sass stylus-loader -D
安装babel
npm i babel-loader @babel/core babel-preset-react-app eslint-config-react-app -D
安装 react
npm i react react-dom
"dependencies": {
"css-loader": "^6.7.1",
"eslint-webpack-plugin": "^3.1.1",
"html-webpack-plugin": "^5.5.0",
"style-loader": "^3.3.1"
},
"devDependencies": {
"@babel/core": "^7.18.2",
"babel-loader": "^8.2.5",
"babel-preset-react-app": "^10.0.1",
"eslint-config-react-app": "^7.0.1",
"less-loader": "^11.0.0",
"postcss-loader": "^7.0.0",
"postcss-preset-env": "^7.7.1",
"sass": "^1.52.3",
"sass-loader": "^13.0.0",
"stylus-loader": "^7.0.0",
"webpack": "^5.73.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.9.2"
}
}
配置启动项 package.json
"scripts": {
"dev":"webpack serve --config ./config/webpack.dev.js"
},
安装定义环境变量库 cross-env
npm install --save-dev cross-env
"scripts": {
"start": "npm run dev",
"dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.dev.js"
},
const path = require("path");
const EslintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const getStyleloaders=(pre)=>{
return [
"style-loader",
"css-loader",
{//css做兼容处理 还需在package.json中browserslist来指定兼容性
loader:'postcss-loader',
options:{
postcssOptions:{
plugins:["postcss-preset-env"],
},
},
},
pre
].filter(Boolean);
}
module.exports={
entry:'./src/main.js',
output:{
path:undefined,
filename:"static/js/[name].js",
chunkFilename:"static/js/[name].chunk.js",//动态import导入的js
assetModuleFilename:"static/media/[hash:10][ext][query]",
},
module:{
rules:[
//处理css
{
test:/\.css$/,
use:getStyleloaders(),
},
{
test:/\.less$/,
use:getStyleloaders('less-loader'),
},
{
test:/\.s[ac]ss$/,
use:getStyleloaders('sass-loader'),
},
{
test:/\.styl$/,
use:getStyleloaders('stylus-loader')
},
//处理图片
{
test:/\.(jpe?g|png|gif|webp|svg)/,
type:"asset",
parser:{
dataUrlCondition:{
maxSize:10*1024,
},
},
},
//处理其他资源
{
test:/\.(woff2?|ttf)/,
type:"asset/resource",
},
//处理js
{
test:/\.jsx?$/,
include:path.resolve(__dirname,'../src'),
loader:'babel-loader',
options:{
cacheDirectory:true,//开启缓存
cacheCompression: false,//不要压缩打包性能更快
},
},
],
},
plugins:[
new EslintWebpackPlugin({
context:path.resolve(__dirname,'../src'),
exclude:"node_modules",//包含排除 指定处理范围
cache:true,//缓存
cacheLocation:path.resolve(__dirname,'../node_modules/.cache/.eslintcache'),//缓存目录
//添加.eslintrc.js 配置
}),
//处理html
new HtmlWebpackPlugin({
template:path.resolve(__dirname,"../public/index.html"),
}),
],
mode: "development", //开发模式
devtool: "cheap-module-source-map", //调试设置
optimization: {
splitChunks:{
chunks:'all', //进行代码分割 主要分割 动态导入的语法
},
//代码分割会导致缓存失效 避免文件的频繁变更导致浏览器缓存失效,
//所以其是更好的利用缓存。提升用户体验。
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}.js`,
},
},
//webpack解析模块加载选项
resolve:{
//自动补全文件扩展名
extensions:[".jsx",".js",".json"],
},
//热更新
devServer: {
open: true,
host: "localhost",
port: 3000,
hot: true, //开启HMR
},
}
JSX 配置HMR(热更新) 功能 React Refresh Webpack Plugin
安装依赖
npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
...
//处理js
{
test:/\.jsx?$/,
include:path.resolve(__dirname,'../src'),
loader:'babel-loader',
options:{
cacheDirectory:true,//开启缓存
cacheCompression: false,//不要压缩打包性能更快
plugins:[
'react-refresh/babel' //激活JSX 的HMR 功能
]
},
},
...
plugins:[
...
//react 热更新
new ReactRefreshWebpackPlugin()
],
...
devServer: {
open: true,
host: "localhost",
port: 3000,
hot: true, //开启HMR
},
前端路由修改
安装配置: npm i react-router-dom
//main.js
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("app"));
root.render(
);
import React from "react";
import { Link,Route,Routes} from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
function App(){
return (
App
- Home
- About
} />
} />
);
}
export default App;
前端路由刷新404问题
配置:
devServer: {
open: true,
host: "localhost",
port: 3000,
hot: true, //开启HMR
historyApiFallback:true,//前端路由刷新404问题
},
}
处理路由组件单独打包 使用路由懒加载
// import React from "react";
import { Link,Route,Routes} from "react-router-dom";
import React,{Suspense,lazy} from "react"; //lazy函数负责定义路由懒加载的组件
// import Home from "./pages/Home";
// import About from "./pages/About";
const Home=lazy(()=>import(/* webpackChunkName:'home'*/ "./pages/Home"));
const About=lazy(()=>import(/* webpackChunkName:'about'*/ "./pages/About"));
function App(){
return (
App
- Home
- About
loading.... }>
} />
} />
搭建生产模式配置
指定输出路径
output:{
path:path.resolve(__dirname,"../dist"),
filename:"static/js/[name].[contenthash:10].js",
chunkFilename:"static/js/[name].[contenthash:10].chunk.js",//动态import导入的js
assetModuleFilename:"static/media/[hash:10][ext][query]",
clean:true,
},
提取CSS成单独文件
、
const MiniCssExtractPlugin =require('mini-css-extract-plugin');
plugins:[
new MiniCssExtractPlugin({
filename:'static/css/[name].[contenthash:10].css',
chunkFilename:'static/css/[name].[contenthash:10].chunk.css'
})
]
处理JS 压缩 CSS 压缩
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); //css压缩
const TerserWebpackPlugin = require("terser-webpack-plugin"); //js压缩
...
optimization: {
splitChunks:{
chunks:'all', //进行代码分割 主要分割 动态导入的语法
},
//代码分割会导致缓存失效 避免文件的频繁变更导致浏览器缓存失效,
//所以其是更好的利用缓存。提升用户体验。
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}.js`,
},
//js压缩
minimizer:[new CssMinimizerPlugin(),new TerserWebpackPlugin()]
},
图片压缩
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
},
},
],
},
],
],
},
},
}),
下载依赖 npm i mini-css-extract-plugin css-minimizer-webpack-plugin -D
下载图片依赖包
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo --save-dev
修改构建启动变量 package.json
"build": "cross-env NODE_ENV=production webpack --config ./config/webpack.prod.js"
运行npm run build 打包 会有路由刷新404问题 需要专门配置
网站配置LOGO 图标 copy-webpack-plugin
安装: npm install copy-webpack-plugin --save-dev
把public下的资源拷贝到dist目录下
const CopyPlugin = require("copy-webpack-plugin");
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "../public"),
to: path.resolve(__dirname, "../dist"),
toType: "dir",
noErrorOnMissing: true, // 不生成错误
globOptions: {
// 忽略文件
ignore: ["**/index.html"],
},
info: {
// 跳过terser压缩js
minimized: true,
},
},
],
}),
//webpack.prod.js
const path = require("path");
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const TerserWebpackPlugin = require("terser-webpack-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const getStyleLoaders = (preProcessor) => {
return [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
preProcessor,
].filter(Boolean);
};
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "../dist"),
filename: "static/js/[name].[contenthash:10].js",
chunkFilename: "static/js/[name].[contenthash:10].chunk.js",
assetModuleFilename: "static/js/[hash:10][ext][query]",
clean: true,
},
module: {
rules: [
{
oneOf: [
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: getStyleLoaders(),
},
{
test: /\.less$/,
use: getStyleLoaders("less-loader"),
},
{
test: /\.s[ac]ss$/,
use: getStyleLoaders("sass-loader"),
},
{
test: /\.styl$/,
use: getStyleLoaders("stylus-loader"),
},
{
test: /\.(png|jpe?g|gif|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
},
},
},
{
test: /\.(ttf|woff2?)$/,
type: "asset/resource",
},
{
test: /\.(jsx|js)$/,
include: path.resolve(__dirname, "../src"),
loader: "babel-loader",
options: {
cacheDirectory: true,
cacheCompression: false,
plugins: [
// "@babel/plugin-transform-runtime" // presets中包含了
],
},
},
],
},
],
},
plugins: [
new ESLintWebpackPlugin({
context: path.resolve(__dirname, "../src"),
exclude: "node_modules",
cache: true,
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
}),
new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:10].css",
chunkFilename: "static/css/[name].[contenthash:10].chunk.css",
}),
// 将public下面的资源复制到dist目录去(除了index.html)
new CopyPlugin({
patterns: [
{
from: path.resolve(__dirname, "../public"),
to: path.resolve(__dirname, "../dist"),
toType: "dir",
noErrorOnMissing: true, // 不生成错误
globOptions: {
// 忽略文件
ignore: ["**/index.html"],
},
info: {
// 跳过terser压缩js
minimized: true,
},
},
],
}),
],
optimization: {
// 压缩的操作
minimizer: [
new CssMinimizerPlugin(),
new TerserWebpackPlugin(),
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
},
},
],
},
],
],
},
},
}),
],
splitChunks: {
chunks: "all",
},
runtimeChunk: {
name: (entrypoint) => `runtime~${entrypoint.name}`,
},
},
resolve: {
extensions: [".jsx", ".js", ".json"],
},
mode: "production",
devtool: "source-map",
};