抛弃Cra从零配置React项目

629 阅读3分钟

引言

我们平常做项目时,经常使用create-react-app脚手架,它可以帮我们快速生成一个零配置的react项目,它的webpack配置文件是对外隐藏的,但是想要针对项目进行优化配置,就需要借助其他工具和插件,比如react-app-rewired,或者运行eject命令,将配置文件暴露出来进行修改。那么怎么不使用脚手架,从零配置一个react项目呢?本文将为你介绍。

1、新建空白目录,并初始化

yarn init -y

2、安装开发依赖

// 打包,本地运行工具
yarn add webpack webpack-cli webpack-dev-server -D

// 安装webpack插件
yarn add html-webpack-plugin  clean-webpack-plugin -D

// babel
yarn add @babel/core babel-loader @babel/preset-env @babel/preset-react -D

// 由于js中的有些api,babel不能转换,所以要用babel-pollyfill,
// 但是pollyfill转换时会造成大量重复代码,所以有了 babel-runtime

// 按装各种loader
yarn add style-loader css-loader scss-loader postcss-loader -D

// 加载图片
file-loader 解决CSS等文件中的引入图片路径问题
url-loader 当图片小于limit的时候会把图片BASE64编码,大于limit参数的时候还是使用file-loader 进行拷贝
yarn add file-loader url-loader -D

// 分离 Css
yarn add mini-css-extract-plugin -D

// 压缩JS和CSS
yarn add terser-webpack-plugin optimize-css-assets-webpack-plugin -D

// 打包前清空build目录
yarn add clean-webpack-plugin -D

// 加css3前缀
yarn add postcss-loader autoprefixer -D

3、引入外部链接,不被webpack打包

// 在html中添加
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>

// 在js中使用
const jQuery = require("jquery");
import jQuery from 'jquery';

// webpack中配置
externals: {
    jquery: 'jQuery'//如果要在浏览器中运行,那么不用添加什么前缀,默认设置就是global
},

4、打包时在html中插入cdn链接,不被webpack打包

// 需要安装 html-webpack-externals-plugin插件
const htmlWebpackExternalsPlugin= require('html-webpack-externals-plugin');
new htmlWebpackExternalsPlugin({
            externals:[
                {
                    module:'react',
                    entry:'https://cdn.bootcss.com/react/15.6.1/react.js',
                    global:'React'
                },
                 {
                    module:'react-dom',
                    entry:'https://cdn.bootcss.com/react/15.6.1/react-dom.js',
                    global:'ReactDOM'
                }
            ]
})

5、最终的webpack配置文件

const path = require('path');
// 处理template 模板
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 抽离css,放到单独文件内
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

// 压缩丑化js代码
const TerserPlugin = require('terser-webpack-plugin')
// 压缩css代码
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')

// 清空build目录
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

const HtmlWebpackExternalsPlugin= require('html-webpack-externals-plugin')


module.exports = {
  mode: 'development',
  entry: './src/index.jsx',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: './'
  },
  devtool: 'source-map',

  // 优化项
  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true,
        cache: true
      }),
      //压缩css资源的
      new OptimizeCSSAssetsPlugin({
        assetNameRegExp:/\.css$/g,
        //cssnano是PostCSS的CSS优化和分解插件。cssnano采用格式很好的CSS,并通过许多优化,以确保最终的生产环境尽可能小。
        cssProcessor: require('cssnano')
      })
    ],
  },

  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        include: path.join(__dirname, 'src'),
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            "presets": ["@babel/preset-env", "@babel/preset-react"],
          }
        }
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: '/'  // 
            }
          }, 'css-loader', 'postcss-loader'],
      },
      {
        test: /\.less$/,
        use: [{loader: MiniCssExtractPlugin.loader}, 'css-loader','postcss-loader', 'less-loader'],
      },
      {
        test:/\.(jpg|png|bmp|gif|svg)/,
          use:[
          {
            loader:'url-loader',
            options:{
              limit: 4096, // 小于4k的图片转成base64编码
              outputPath: 'images',
              publicPath: './images'
            } 
          }
        ]
      }
    ]
  },
  
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './src/index.html', // 源文件
      filename: 'index.html', // 产出文件
      hash: true, //避免缓存,在产出的资源后加hash
    }),

    // 将css抽离成单个文件
    new MiniCssExtractPlugin({
      filename: 'css/[name].css',
      chunkFilename:'css/[id].css'
    }),

    new HtmlWebpackExternalsPlugin({
      externals:[
          {
              module:'react',
              entry:'https://cdn.bootcss.com/react/15.6.1/react.js',
              global:'React'
          },
           {
              module:'react-dom',
              entry:'https://cdn.bootcss.com/react/15.6.1/react-dom.js',
              global:'ReactDOM'
          }
      ]
    }) 

  ],
  devServer: {
    port: 3000,
    // 设置跨域请求,代理
    "/api": {
      target: 'http://localhost:3000',
      pathRewrite:{"^/api":""}        
   } 
  },

  // 重要:
  resolve: {
    // 可以在require和 import的时候不用加后缀,会从前往后找
    extensions: [".js",".jsx",".json",".css"]
  },

};

6、最终package.json文件

{
  "name": "custom",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "webpack-dev-server",
    "build": "webpack"
  },
  "dependencies": {
    "@babel/core": "^7.8.6",
    "@babel/preset-env": "^7.8.6",
    "babel-loader": "^8.0.6",
    "react": "^16.13.0",
    "react-dom": "^16.13.0",
    "react-router": "^5.1.2"
  },
  "devDependencies": {
    "@babel/preset-react": "^7.8.3",
    "autoprefixer": "^9.7.4",
    "clean-webpack-plugin": "^3.0.0",
    "css-loader": "^3.4.2",
    "file-loader": "^5.1.0",
    "html-webpack-externals-plugin": "^3.8.0",
    "html-webpack-plugin": "^3.2.0",
    "less": "^3.11.1",
    "less-loader": "^5.0.0",
    "mini-css-extract-plugin": "^0.9.0",
    "optimize-css-assets-webpack-plugin": "^5.0.3",
    "postcss-loader": "^3.0.0",
    "sass-loader": "^8.0.2",
    "scss-loader": "^0.0.1",
    "style-loader": "^1.1.3",
    "terser-webpack-plugin": "^2.3.5",
    "url-loader": "^3.0.0",
    "webpack": "^4.41.6",
    "webpack-cli": "^3.3.11",
    "webpack-dev-server": "^3.10.3"
  }
}