likes
comments
collection
share

一个 WebPack5+Typescript5+React18的前端工程

作者站长头像
站长
· 阅读数 22

最近在整理自己之前的一些demo,想整一个模板工程出来,方便随时使用。之前也有用一些快速创建的脚手架,但是发现要做一些特殊配置和修改总是很麻烦,所以就自己在试着搭了一个。地址

目录结构

+--- README.md                 说明文档
\--- build                     webpack相关配置
    +--- webpack.prod.js       生产环境配置
    +--- webpack.dev.js        开发环境配置
    +--- webpack.dll.conf.js   dll生成配置,用于生成dll
    +--- webpack.base.js       基础配置  
+--- package.json            依赖说明文件
+--- public                  基础配置文件
+---build webpack相关配置
\---src 主要开发文件
    +---api                 axios 请求封装
    +---component           功能组件
    +---hooks               自定义钩子
    +---pages               页面组件
    +---router              路由配置,(新增页面,需要在这进行配置,
    +---utils               一些工具方法
+---.prettierrc             格式化配置
+---.eslintrc               代码检测配置
+---.gitignore              git忽略
+---tsconfig.json           ts配置
+---.env                    基础环境变量
+---dev.env                 开发环境变量
+---prod.env                生产环境变量

主要文件配置,及说明

webpack.base.js
  1. base中,读取并设置了写在.env里的全局变量
  2. 配置了地址别名src,因为使用的ts,所以在tsConfig.json中也要进行相应的配置
  3. 配置了常用的loader,ts-loader、babel-loader、sass-loader、css-loader
  4. 配置常用plugin,
const path = require('path');// 路径
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');//  生成HTML文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');// css压缩
const { CleanWebpackPlugin } = require('clean-webpack-plugin');// 打包清理,删除dist目录
const dotenv = require('dotenv');
// 获取环境变量,projectRoot当前目录
const projectRoot = process.cwd();
const shared = {
    include: path.resolve(projectRoot, 'src'),
    exclude: /node_modules/,
};
// 解析env配置文件,设置环境变量
try {
    dotenv.config({ path: 'base.env' }); // 加载 .env 文件
    if (process.env.NODE_ENV === 'development') {
       dotenv.config({ path: 'dev.env' });
    } else {
       dotenv.config({ path: 'prod.env' });
    }
} catch (error) {
    throw new Error(`读取环境变量文件失败${error}`);
}
module.exports = {
    entry: `${projectRoot}/src/index.tsx`,
    cache: {
       type: 'filesystem',// 使用文件缓存
    },
    output: {
       filename: '[name].[chunkhash:8].js', // 打包后的文件名称
       path: path.resolve(projectRoot, './dist'), // 打包后的目录
       clean: true,
    },
    resolve: {
       extensions: ['.tsx', '.ts', '.js'],
       alias: {
          src: path.resolve(projectRoot, 'src'),//使用src作为地址别名
       },
    },
    module: {
       rules: [
          {
             test: /.tsx?$/,
             use: [
                {
                   loader: 'ts-loader',
                   options: {
                      transpileOnly: true,
                   },
                },
             ],
             ...shared,
          },
          {
             test: /.js$/,
             use: 'babel-loader',
             ...shared,
             issuer: /.[tj]sx?$/,
          },
          {
             test: /.s[ac]ss|css$/i,
             ...shared,
             use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
             issuer: /.[tj]sx?$/,
          },
          {
             test: /.(png|svg|jpg|gif)$/,
             ...shared,
             type: 'asset/resource',
          },
          {
             test: /.(woff|woff2|eot|ttf|otf)$/,
             type: 'asset/resource',
             ...shared,
          },
       ],
    },
    plugins: [
       /* 根据模板生成HTML文件,模板可不传 */
       new HtmlWebpackPlugin({
          template: `${projectRoot}/public/index.html`,
       }),
       /* css 文件合并  */
       new MiniCssExtractPlugin({
          filename: '[name].[contenthash:8].css',
       }),
       // 定义环境变量,在项目文件中使用
       new webpack.DefinePlugin({
          'process.env.SERVER_URL': JSON.stringify(process.env.SERVER_URL),
          'process.env.MODE': JSON.stringify(process.env.MODE),
       }),
       new CleanWebpackPlugin(),
       function errorPlugin() {
          // 打包错误提示
          this.hooks.done.tap('done', stats => {
             if (
                stats.compilation.errors &&
                stats.compilation.errors.length &&
                process.argv.indexOf('--watch') === -1
             ) {
                console.error(stats.compilation.errors); //错误信息
                process.exit(2);
             }
          });
       },
    ],
    stats: 'errors-only',
};
webpack.dev.js
  1. 合并了上一步的基础配置,添加了开发代理,
  2. 后续有开发阶段的配置也可以加在这里
const { merge } = require('webpack-merge');
const baseConfig = require('./webpack.base.js');
const defConfig = merge(baseConfig, {
    mode: 'development',
    devtool: 'source-map',//开启sourceMap,方便调试
    devServer: {
       proxy: [
          {
             context: ['/api', '/aa'],//代理
             target: process.env.TEST_SERVER_URL,//在dev.env中配置
             changeOrigin: true,
             pathRewrite: { '^/api': '/api' },//根据自己后台配置
          },
       ],
    },
});
module.exports = defConfig;
webpack.prod.js
  1. 添加一些打包优化方式,terser-webpack-plugin 提高打包速度
  2. webpack.DllReferencePlugin 缓存文件
const { merge } = require('webpack-merge');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const webpack = require('webpack');
const baseConfig = require('./webpack.base.js');
const TerserPlugin = require('terser-webpack-plugin');
//使用dll,必须在打包前先生成manifest webpack --config .\build\webpack.dll.conf.js
const manifest = require('./dist/vendor.manifest.json');
const prodConfig = merge(baseConfig, {
    mode: 'production',
    optimization: {
       minimizer: [new TerserPlugin({//使用terser进行压缩
          minify: TerserPlugin.swcMinify,
          terserOptions: {},
       })],
       splitChunks: {
          minSize: 10, // 当文件大小小于该值时,不会生成单独的chunk文件
          cacheGroups: {
             commons: {
                // 对使用的公共文件进行抽离
                name: 'commons',
                chunks: 'all',
                minChunks: 2, // 最小公共次数
             },
          },
       },
    },
    plugins: [
       // 生成dll
       new webpack.DllReferencePlugin({
          context: __dirname,
          manifest,// manifest 就是之前打包出来的 json 文件
       }),
       /* css压缩 */
       new CssMinimizerPlugin({
          test: /.css$/,
       }),
    ],
})
module.exports = prodConfig;
webpack.dll.conf
  1. 使用DllPlugin 可以将特定的类库提前打包然后引入
const path = require('path');
const webpack = require('webpack');
module.exports = {
    mode: 'production',
    entry: {
       vendor: ['react', 'react-dom'], // 将你想要打包的第三方库列在这里
    },
    output: {
       filename: '[name].dll.js',
       path: path.resolve(__dirname, 'dist'),
       library: '[name]_dll', // 将输出的 DLL 模块名设为全局变量
    },
    plugins: [
       new webpack.DllPlugin({
          name: '[name]_dll',
          path: path.resolve(__dirname, 'dist', '[name].manifest.json'),
       }),
    ],
};
首次 yarn build之前,需要 webpack --config webpack.dll.conf.js生成依赖文件
tsconfig.json
  • 配置地址别名必填项 baseUrlpaths(要和webpack.base.js里一一对应)
{
    "exclude": [
       "node_modules",
       "dist"
    ],
    "include": [
       "src"
    ],
    "compilerOptions": {
       "outDir": "./dist/",
       "noImplicitAny": true,
       "target": "es5",
       "baseUrl": ".",
       "paths": {
          "src/*": [
             "src/*"
          ]
       },
       "lib": [
          "dom",
          "dom.iterable",
          "esnext"
       ],
       "allowJs": true,
       "skipLibCheck": true,
       "esModuleInterop": true,
       "allowSyntheticDefaultImports": true,
       "strict": true,
       "forceConsistentCasingInFileNames": true,
       "noFallthroughCasesInSwitch": true,
       "module": "esnext",
       "moduleResolution": "node",
       "resolveJsonModule": true,
       "isolatedModules": true,
       "noEmit": false,
       "jsx": "react-jsx"
    }
}
packge.json
  • 根据目录结构,配置好start、build
"scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "start": "webpack-dev-server --config ./build/webpack.dev.js    --hot --open ",
    "build": "webpack --config ./build/webpack.prod.js",
    "dll": "webpack --config ./build/webpack.dll.conf.js",
    "lint": "eslint "src/**/*.{js,ts,tsx}" --fix"
},

快速开始

  • 克隆下来就可以直接使用
  • axios,和模板页面都是现成的
    git clone https://github.com/mobei12/React-ts-webpack.git

欢迎留言共同进步 🤝