Webpack5 搭建 React18(typescript) 开发环境

in JavaScript with 0 comment

现在react开发,公司用的要么是create-react-app这个脚手架,要么是umi,这些脚手架也是基于webpack的,只是添加了一些实践中比较好用功能进去,最近就想研究一下怎么通过webpack从0到1搭建一套适合自己的React开发环境。

这次探索使用的主要软件及版本如下:

Node: v14

Webpack: v5.72.0

React: v18

Babel: v7

typescript:v4.6.3

Babel 7 配置

这是想重点说一下Babel 7的配置,这个还是有点让人疑惑的,先看结论


广大前端工程人员babel终极配置:

"presets": [['@babel/preset-env', {targets: "ie 11","useBuiltIns": "usage", "corejs": "3.6" }]]

需要安装的包有

@babel/runtime  引入helpers函数 必须
npm install --save core-js@3  配置中指定的corejs版本
@babel/preset-env  预设
@babel/core  核心
babel-loader  webpack处理core-js的loader


广大js库开发者终极配置:


presets: ['@babel/preset-env'],
"plugins": [
[
    "@babel/plugin-transform-runtime",
    {
      "helpers": true,
      "corejs": 3,
      "regenerator": true,
      "useESModules": false,
      "absoluteRuntime": false,
      "version": "^7.17.9"
    }
  ]
]


Babel7的配置感觉babel的官网说的并不是太清楚,对于没有babel配置经验的人来说,很难分清楚各种配置项的含义,好在babel7已经大大的简化了相关polyfill的引入,我是通过这篇文章才算理解了babel的正确配置,见链接 babel教程

webpack.common.config.js

下边直接贴出webpack.common.config.js的配置,webpack区分dev环境和prod环境,webpack.common.config.js是公共配置

这里主要配置了项目入口 ,项目打包配置,ts的支持(babel-loader和ts-loader),图片,字体等静态资源等配置


const path = require("path");
const webpack = require("webpack");
const chalk = require("chalk");
const HtmlWebpackPlugin = require("html-webpack-plugin");
//这个要node12以上了
//const EslintWebpackPlugin = require('eslint-webpack-plugin');
const ProgressBarPlugin = require("progress-bar-webpack-plugin");

/** @type {(import('webpack').Configuration} */
const config = {
  entry: path.resolve(__dirname, "../src/index.tsx"), // 默认入口,如果一样可以不设置
  output: {
    // 出口
    path: path.resolve(__dirname, "../dist"), //  默认打包文件夹,如果一样可以不设置
    //filename: 'main.js' //  默认打包目录文件名,如果一样可以不设置
    filename: "js/[name].bundle.js",
    assetModuleFilename: "images/[name].[ext][query]",
    publicPath: "/",
    clean: true,
  },
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "../src"), // 同时配置 '@' 符号作为 src 的绝对路径别名方便后续开发
    },
    extensions: [".ts", ".tsx", ".js", ".json"],
  },
  module: {
    rules: [
      {
        test: /\.tsx?$/, //
        exclude: /node_modules/, // 排除 node_modules 目录
        use: [
          {
            loader: "babel-loader",
          },
          //这里使用ts-loader,内部还是调用tsc进行编译,还可选用 @babel/preset-typescript ,这用就不用安装typescript了
          // https://blog.logrocket.com/babel-vs-typescript/
          {
            loader: "ts-loader",
          },
        ],
      },
      {
        test: /\.(png|jpe?g|gif)$/,
        type: "asset/resource",
      },
      {
        test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
        type: "asset/inline",
      },
    ],
  },
  plugins: [
    //会在dist生成一个一样的index.html
    new HtmlWebpackPlugin({
      //template: "./public/index.html"
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    // new EslintWebpackPlugin({
    //   fix: true, // fix 参数能够自动修复部分错误
    //   extensions: ['js', 'ts', 'tsx'], // 需要检测的文件类型
    //   // 更多参数可以去查看 https://webpack.docschina.org/plugins/eslint-webpack-plugin/#root
    // }),
    new ProgressBarPlugin({
      format: ` build [:bar] ${chalk.green.bold(
        ":percent"
      )} (:elapsed seconds)`,
    }),
  ],
  stats: "minimal",
};

module.exports = config;


webpack.dev.config.js

这里主要是开发环境的相关配置,如热启动,路由模式,代理,css预处理(sass/less/postcss/autoprefixer)等。


const { merge } = require("webpack-merge");
const common = require("./webpack.common.config");
// const path = require("path");
module.exports = merge(common, {
  mode: "development",
  devtool: "source-map",
  devServer: {
    port: 9900, // 指定端口
    open: false, // 自启浏览器
    hot: true, // 局部热更新
    compress: false,
    historyApiFallback: true, // 支持 history 模式路由
    // client: {
    //   logging: 'none'
    // }
    proxy: {
      // 代理跨域 如果需要的话
      "/insight": {
        // target: "https://zen.kyligence.io/", // 目标代理接口地址
        target: "https://api.zongliwei.com/api/v2/", // 目标代理接口地址
        changeOrigin: true, // 是否跨域
        pathRewrite: {
          // "^/api": "/",
        },
      },
    },
  },
  module: {
    rules: [
      // {
      //   //test: /\.(css|sass|scss)$/,
      //   test: /\.(sa|sc|c)ss$/,
      //   use: [
      //     "style-loader", // 把css内嵌到html的style标签中
      //     // 普通的css 会应用css-loader import 'a.css'  img:url() 这种
      //     //css有不少高级用法,例如生成hash的类名 https://www.npmjs.com/package/css-loader
      //     {
      //       loader: "css-loader",
      //       options: {
      //         sourceMap: true, // 启用 css sourceMap
      //       },
      //     },
      //     {
      //       loader: "postcss-loader",
      //       options: {
      //         postcssOptions: {
      //           plugins: [
      //             [
      //               "autoprefixer",
      //               {
      //                 overrideBrowserslist: ["last 4 version"],
      //               },
      //             ],
      //           ],
      //         },
      //       },
      //     },
      //     "sass-loader",
      //   ],
      //   exclude: /node_modules/,
      // },
      {
        test: /\.(css|less)$/,
        use: [
          "style-loader", // 把css内嵌到html的style标签中
          // 普通的css 会应用css-loader import 'a.css'  img:url() 这种
          {
            loader: "css-loader",
            options: {
              // sourceMap: true, // 启用 css sourceMap
              modules: {
                auto: true,
                localIdentName: "[local]__[hash:base64:6]",
              },
            },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  [
                    "autoprefixer",
                    {
                      overrideBrowserslist: ["last 4 version"],
                    },
                  ],
                ],
              },
            },
          },
          {
            loader: "less-loader",
            options: {
              // webpackImporter: true,
              lessOptions: {
                javascriptEnabled: true,
              },
            },
          },
        ],
        // include: [path.resolve(__dirname, "src", "less")],
        // exclude: /node_modules/,
      },
    ],
  },
});


webpack.prod.config.js

这里主要配置了生产环境的相关优化,比如禁用source-map,js/css 压缩,定义打包文件名(hash) 等


const { merge } = require("webpack-merge");
//const path = require("path");
const common = require("./webpack.common.config");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = merge(common, {
  mode: "production",
  devtool: false, // 生产环境不需要 source-map
  //js 代码压缩要用到 terser-webpack-plugin,但 webpack 5 内置了这个插件可一键开启
  optimization: {
    //生产环境开启terser-webpack-plugin
    minimize: true,
  },
  output: {
    filename: "js/app.js",
    //filename: path.resolve(__dirname, "js/app.js"),
    assetModuleFilename: "images/[name].[ext][query]",
    //filename: 'js/[name].[contenthash].bundle.js', // 文件名哈希
    //assetModuleFilename: 'images/[name].[contenthash][ext][query]', // 图片文件需要存放的位置,如果不设置会全部打包进根目录下
    //publicPath: '/app/'
  },
  module: {
    rules: [
      {
        //test: /\.(css|sass|scss)$/,
        test: /\.(sa|sc|c)ss$/,
        use: [
          "style-loader", // 把css内嵌到html的style标签中
          // 普通的css 会应用css-loader import 'a.css'  img:url() 这种
          //css有不少高级用法,例如生成hash的类名 https://www.npmjs.com/package/css-loader
          {
            loader: "css-loader",
            options: {
              sourceMap: true, // 启用 css sourceMap
            },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  [
                    "autoprefixer",
                    {
                      overrideBrowserslist: ["last 4 version"],
                    },
                  ],
                ],
              },
            },
          },
          "sass-loader",
        ],
        exclude: /node_modules/,
      },
      {
        //test: /\.(css|sass|scss)$/,
        test: /\.less$/,
        use: [
          "style-loader", // 把css内嵌到html的style标签中
          // 普通的css 会应用css-loader import 'a.css'  img:url() 这种
          {
            loader: "css-loader",
            options: {
              sourceMap: true, // 启用 css sourceMap
            },
          },
          {
            loader: "postcss-loader",
            options: {
              postcssOptions: {
                plugins: [
                  [
                    "autoprefixer",
                    {
                      overrideBrowserslist: ["last 4 version"],
                    },
                  ],
                ],
              },
            },
          },
          {
            loader: "less-loader",
            options: {
              lessOptions: {
                javascriptEnabled: true,
              },
            },
          },
        ],
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    // 启用 css 压缩插件
    new MiniCssExtractPlugin({
      filename: "css/[name].[contenthash].css",
      //filename: './app.css'
    }),
  ],
});


如何使用css modules (可配置css类名hash)

  1. 在global.t.ds中定义 "*.module.less"
  2. 把less文件名改为 xx.module.less
  3. 在文件中引入的时候用 import classes from 'xx.module.less'
  4. tsx中引入的时候用 classes['cls-name']
  5. webpack.dev.config.js中配置如下
options: {
  // sourceMap: true, // 启用 css sourceMap
  modules: {
    auto: true,
    localIdentName: "[local]__[hash:base64:6]",
  },
},

如果不想用css modules,则把文件名改为 xx.less ,其它恢复成原样即可

脚手架地址: webpack-react-scaffolding

评论已关闭.