WebPack项目实战配置

webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const EslintWebpackPlugin = require('eslint-webpack-plugin');
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

// 获取cross-env定义的环境变量
const isProduction = process.env.NODE_ENV === 'production';

//排除的文件
const pubExcludeFiles = [
  path.resolve(__dirname, '../node_modules/antd/dist'),
  path.resolve(__dirname, '../src/style'),
];

//包含的文件
const pubIncludeFiles = [
  path.resolve(__dirname, '../node_modules/antd/dist'),
  path.resolve(__dirname, '../src/style'),
];

// 返回处理样式loader函数
const getStyleLoaders = (pre) =>
  [
    isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
    //解决react 样式 冲突 CssModule
    {
      loader: 'css-loader',
      options: {
        modules: {
          localIdentName: '[path][name]-[local]', //--[hash:base64:5]
        },
      },
    },
    // 配合package.json中browserslist来指定兼容性
    {
      loader: 'postcss-loader',
      options: {
        postcssOptions: {
          plugins: ['postcss-preset-env'],
        },
      },
    },
    pre && {
      loader: pre,
      options:
        pre !== 'less-loader'
          ? {
              additionalData: '@import "./src/scss/cssVars.scss"; ',
              sassOptions: {
                includePaths: [path.resolve(__dirname, 'src/scss')],
              },
            }
          : {},
    },
  ].filter(Boolean);

module.exports = {
  entry: {
    main: [path.resolve(__dirname, '../src/main.js')],
  },
  target: 'web',
  output: {
    path: isProduction ? path.resolve(__dirname, '../dist') : undefined,
    filename: isProduction ? 'static/js/[name].[contenthash:10].js' : 'static/js/[name].js',
    chunkFilename: isProduction
      ? 'static/js/[name].[contenthash:10].chunk.js'
      : 'static/js/[name].chunk.js',
    assetModuleFilename: 'static/media/[hash:10][ext][query]',
    clean: true,
    // libraryTarget: 'umd' // 添加输出库配置
  },
  module: {
    rules: [
      // 处理css
      //其他文件夹 css设置模块化   node_modules css禁止模块化
      {
        test: /\.css$/,
        exclude: pubExcludeFiles,
        use: getStyleLoaders(),
      },
      {
        test: /\.less$/,
        exclude: pubExcludeFiles,
        use: getStyleLoaders('less-loader'),
      },
      {
        test: /\.s[ac]ss$/,
        exclude: pubExcludeFiles,
        use: getStyleLoaders('sass-loader'),
      },
      {
        test: /\.(css|less)$/,
        include: pubIncludeFiles,
        use: [
          'style-loader',
          'css-loader',
          {
            loader: 'less-loader',
            options: {
              lessOptions: {
                javascriptEnabled: true,
              },
            },
          },
        ],
      },
      {
        test: /\.s[ac]ss$/,
        include: pubIncludeFiles,
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
      // 处理图片
      {
        test: /\.(jpe?g|png|gif|webp|svg)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 20 * 1024,
          },
        },
      },
      // 处理其他资源
      {
        test: /\.(woff2?|ttf)$/,
        type: 'asset/resource',
      },
      // 处理js
      {
        test: /\.jsx?$/,
        include: path.resolve(__dirname, '../src'),
        loader: 'babel-loader',
        options: {
          cacheDirectory: true,
          cacheCompression: false,
          plugins: [
            !isProduction && 'react-refresh/babel', // 激活js的HMR
          ].filter(Boolean),
        },
      },
    ],
  },

  plugins: [
    new EslintWebpackPlugin({
      context: path.resolve(__dirname, '../src'),
      exclude: 'node_modules',
      cache: true,
      cacheLocation: path.resolve(__dirname, '../node_modules/.cache/.eslintcache'),
    }),
    // 处理html
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../public/index.html'),
      publicPath: isProduction ? '/YZQ/test/' : '/',
    }),
    isProduction &&
      new MiniCssExtractPlugin({
        filename: 'static/css/[name].[contenthash:10].css',
        chunkFilename: 'static/css/[name].[contenthash:10].chunk.css',
      }),
    !isProduction && new ReactRefreshWebpackPlugin(), //热更新  React组件
    new CopyPlugin({
      patterns: [
        {
          from: path.resolve(__dirname, '../public'), //打包的静态资源目录地址
          to: path.resolve(__dirname, '../dist/public'), //打包到 dist
          globOptions: {
            // 忽略index.html文件
            ignore: ['**/index.html'],
          },
        },
      ],
    }),
    //webpack 5 以前的版本包含 polyfills。
    new NodePolyfillPlugin(),
  ].filter(Boolean),
  mode: isProduction ? 'production' : 'development',
  devtool: isProduction ? false : 'cheap-module-source-map', //线上版本不生成map文件
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        // react react-dom react-router-dom 一起打包成一个js文件
        react: {
          test: /[\\/]node_modules[\\/]react(.*)?[\\/]/,
          name: 'chunk-react',
          priority: 100,
        },
        // antd 单独打包
        antd: {
          test: /[\\/]node_modules[\\/]antd[\\/]/,
          name: 'chunk-antd',
          priority: 90,
        },
        // echarts 单独打包
        echarts: {
          test: /[\\/]node_modules[\\/]echarts(-*)?[\\/]/,
          name: 'chunk-echarts',
          priority: 80,
        },
        // 剩下node_modules单独打包
        libs: {
          test: /[\\/]node_modules[\\/]/,
          name: 'chunk-libs',
          priority: 10,
        },
      },
    },
    runtimeChunk: {
      name: (entrypoint) => `runtime~${entrypoint.name}.js`,
    },
    // 是否需要进行压缩
    minimize: isProduction,
    minimizer: [new CssMinimizerWebpackPlugin(), new TerserWebpackPlugin()],
  },
  // webpack解析模块加载选项
  resolve: {
    // 自动补全文件扩展名
    extensions: ['.jsx', '.js', '.json'],
    // 设置别名
    alias: {
      '@': path.resolve(__dirname, '../src'),
      // '@assets': path.resolve(__dirname, '../src/assets')
    },
  },
  devServer: {
    host: 'localhost',
    port: 8001,
    open: true,
    hot: true, // 开启HMR
    historyApiFallback: true, // 解决前端路由刷新404问题
    // proxy: {
    //   '/api': {
    //     target: 'https://h5up.easy-h5.com', // 后台服务地址以及端口号
    //     // ws: true,
    //     // changeOrigin: true, //是否跨域
    //     pathRewrite: { '^/api': '/' },
    //   },
    // },
  },
  performance: false, // 关闭性能分析,提升打包速度
};

package.json
{
  "name": "react-cli",
  "version": "1.0.0",
  "description": "个人项目框架",
  "keywords": [],
  "license": "ISC",
  "author": "",
  "main": "main.js",
  "scripts": {
    "bui": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js",
    "buildapp:dev": "npm run bui",
    "startapp:dev": "npm run dev",
    "dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.config.js",
    "lint:eslint": "eslint --ext .js,.jsx,.ts,.tsx ",
    "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style",
    "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
    "lint:prettier": "check-prettier lint",
    "lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
    "prettier": "prettier -c --write \"**/*\"",
    "removeUnUseVars": "remove-unexpected-variable.rmjsvar"
  },
  "browserslist": [
    "last 2 version",
    "> 1%",
    "not dead"
  ],
  "dependencies": {
    "@ant-design/icons": "^4.7.0",
    "@antv/g6": "^4.3.11",
    "@reduxjs/toolkit": "^1.8.5",
    "amfe-flexible": "^2.2.1",
    "animate.css": "^4.1.1",
    "antd": "^4.20.3",
    "axios": "^0.22.0",
    "echarts": "^5.2.1",
    "echarts-for-react": "^3.0.1",
    "i18next": "^22.4.15",
    "js-export-excel": "^1.1.4",
    "moment": "^2.29.3",
    "prop-types": "^15.8.1",
    "qg-react-components": "^0.1.3",
    "qs": "^6.10.1",
    "react": "^18.1.0",
    "react-dom": "^18.1.0",
    "react-i18next": "^12.2.2",
    "react-redux": "^8.0.2",
    "react-router-dom": "^6.3.0",
    "react-router-redux": "^4.0.8",
    "redux": "^4.2.0",
    "redux-persist": "^6.0.0",
    "terser-webpack-plugin": "^5.3.6",
    "uuid": "^8.3.2"
  },
  "devDependencies": {
    "@babel/core": "^7.19.1",
    "@babel/eslint-parser": "^7.19.1",
    "@babel/plugin-syntax-flow": "^7.14.5",
    "@babel/plugin-transform-react-jsx": "^7.14.9",
    "@babel/preset-env": "^7.19.1",
    "@babel/preset-react": "^7.18.6",
    "@pmmmwh/react-refresh-webpack-plugin": "^0.5.5",
    "@trivago/prettier-plugin-sort-imports": "^3.3.0",
    "@umijs/fabric": "^3.0.0",
    "babel-eslint": "^10.1.0",
    "babel-loader": "^8.2.5",
    "babel-plugin-syntax-dynamic-import": "^6.18.0",
    "babel-preset-react-app": "^10.0.1",
    "browserslist": "^4.21.4",
    "copy-webpack-plugin": "^11.0.0",
    "cross-env": "^7.0.3",
    "css-loader": "^6.7.1",
    "css-minimizer-webpack-plugin": "^3.4.1",
    "eslint": "^8.23.1",
    "eslint-config-prettier": "^8.5.0",
    "eslint-config-react-app": "^7.0.1",
    "eslint-plugin-prettier": "^4.2.1",
    "eslint-plugin-react": "^7.31.10",
    "eslint-webpack-plugin": "^3.1.1",
    "html-webpack-plugin": "^5.5.0",
    "less": "^3.0.0",
    "less-loader": "^8.0.0",
    "mini-css-extract-plugin": "^2.6.0",
    "node-polyfill-webpack-plugin": "^2.0.1",
    "postcss": "^8.4",
    "postcss-loader": "^6.2.1",
    "postcss-modules-values": "^4.0.0",
    "postcss-preset-env": "^7.5.0",
    "postcss-scss": "^4.0.5",
    "prettier": "^2.4.1",
    "react-refresh": "^0.13.0",
    "sass": "^1.51.0",
    "sass-loader": "^12.6.0",
    "style-loader": "^3.3.1",
    "stylelint": "^14.3.0",
    "stylelint-config-prettier": "^9.0.3",
    "stylelint-config-standard": "^24.0.0",
    "stylelint-order": "^5.0.0",
    "stylus": "^0.59.0",
    "stylus-loader": "^6.2.0",
    "webpack": "^5.72.0",
    "webpack-cli": "^4.9.2",
    "webpack-dev-server": "^4.9.0"
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值