React项目识别'@'路径提示以及项目打包优化

背景:本篇博客针对React项目的一些配置:
在react项目中使用'@'代替src路径
打包上线后去除控制台console.log() ,路由懒加载 ,CDN等优化
redux使用

redux路由使用,传参

1. 用craco来配置路径别名'@'

在React脚手架项目中:
CRA(create-react-app) 将所有工程化配置,都隐藏在了 react-scripts 包中,所以,项目中看不到任何配置信息或者是配置文件。

如果要修改 CRA 的默认配置,有以下几种方案:

  1. 【推荐】通过第三方库来修改,比如,@craco/craco
  2. 通过执行 yarn eject 命令,释放 react-scripts 中的所有配置到项目中(注意:该操作不可逆!!!)

1.craco:

craco是对create-react-app进行自定义配置的一款工具。

2.craco的使用步骤

  1. 安装包。npm i -D @craco/craco

  2. 在项目根目录下,创建配置文件:craco.config.js。在配置文件中就可以做自定义的修改了。

    craco.config.js中配置路径别名:

const path = require('path')
module.exports = {
  webpack: {
    alias: {
      '@': path.join(__dirname, 'src')
    }
  }
}
复制代码

3.修改 package.json 中的脚本命令

package.json 中:

// 将 start/build/test 三个命令修改为 craco 方式

"scripts": {
  "start": "craco start",
  "build": "craco build",
  "test": "craco test",
  "eject": "react-scripts eject"
}
复制代码
  1. 在代码中,就可以通过 @ 来表示 src 目录的绝对路径
  2. 重启项目,让配置生效

2.vscode识别@并提示路径

vscode打开配置过craco的react项目中不会对@路径提示,需要在根目录下配置jsconfig.json文件:

// VSCode 会自动读取 `jsconfig.json` 中的配置,让 vscode 知道 @ 就是 src 目录
{
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}
复制代码

3.React项目打包和优化

1.项目打包:

  1. 在项目根目录打开终端,输入打包命令:npm run build(实际命令需查看package.json文件)
  2. 等待打包完成,打包后的内容被放在项目根下的 build 文件夹中

2.项目预览:

  1. 全局安装本地服务包:npm i -g serve,该包提供了 serve 命令,用来启动本地服务
  2. 在项目根目录中执行命令:serve -s ./build,在 build 目录中开启服务器
  3. 在浏览器中 预览项目

3.打包体积分析

通过分析打包体积,才能知道项目中的哪部分内容体积过大,才能知道如何来优化

  1. 安装分析打包体积的包:npm i source-map-explorer
  2. 在 package.json 中的 scripts 标签中,添加分析打包体积的命令:
"scripts": {
  "analyze": "source-map-explorer 'build/static/js/*.js'",
}
复制代码
  1. 对项目打包:npm run build(如果已经打过包,可省略这一步)
  2. 运行分析命令:npm run analyze
  3. 通过浏览器打开的页面,分析图表中的包体积

4.生产环境优化

根据是否为生产环境对redux中的thunk中间件进行优化,
有关reduxthunk中间件,请参考React中redux的使用

let middlewares

if (process.env.NODE_ENV === 'production') {
  // 生产环境,只启用 thunk 中间件
  middlewares = applyMiddleware(thunk)
} else {
  middlewares = composeWithDevTools(applyMiddleware(thunk))
}
复制代码

5.路由懒加载

  1. App 根组件中,导入 Suspense 组件
  2. Router 内部,使用 Suspense 组件包裹组件内容
  3. Suspense 组件提供 fallback 属性,指定 loading 占位内容(加载缓慢是页面显示的内容)
  4. 导入 lazy 函数,并修改为懒加载方式导入路由组件
// 导入lazy 和 Suspense组件
import { lazy, Suspense } from 'react'

// lazy导入页面组件
const Login = lazy(() => import('./pages/Login'))
const Layout = lazy(() => import('./pages/Layout'))

const App = () => {
  return (
    <Router>
      <Suspense
        fallback={
          <div
            style={{
              textAlign: 'center',
              marginTop: 200
            }}
          >
            loading...  // fallback属性配置的加载时显示的内容
          </div>
        }
      >
        <div className="app">
          <Route path="/login" component={Login}></Route>
          <Route path="/home" component={Layout}></Route>
        </div>
      </Suspense>
    </Router>
  )
}
export default App
复制代码

6.去除控制台console

这里借助terser-webpack-plugin包实现去除console.log()一下是webpack关于terser-webpack-plugin的描述:

webpack v5 开箱即带有最新版本的 terser-webpack-plugin。如果你使用的是 webpack v5 或更高版本,同时希望自定义配置,那么仍需要安装 terser-webpack-plugin。如果使用 webpack v4,则必须安装 terser-webpack-plugin v4 的版本。

注意 : 配置之前需要确实使用的webpack是哪个版本,安装对应的版本包:
npm i [email protected]

craco.config.js的文件中配置如下(craco.config.js文件在上面配置了craco):

const path = require('path')
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
  webpack: {
  // 配置识别 @ 路径
    alias: {
      '@': path.join(__dirname, 'src')
    },

    plugins: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: process.env.NODE_ENV === 'production'
            // 生产环境下移除控制台所有的内容
          }
        }
      })
    ]
  }
}
复制代码

7.配置CDN

完整craco.js文件

const path = require('path')
const TerserPlugin = require('terser-webpack-plugin')
const { whenProd, getPlugin, pluginByName } = require('@craco/craco')
module.exports = {
  webpack: {
  // 识别@
    alias: {
      '@': path.join(__dirname, 'src')
    },
    // 移出console.log()
    plugins: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: process.env.NODE_ENV === 'production'
            // 生产环境下移除控制台所有的内容
          }
        }
      })
    ],
    // CDN
    configure: (webpackConfig) => {
      let cdn = {
        js: [],
        css: []
      }
      // 对webpack进行配置
      whenProd(() => {
        // 只会在生产环境执行
        webpackConfig.externals = {
          react: 'React',
          'react-dom': 'ReactDOM',
          redux: 'Redux'
        }
        cdn = {
          js: [
            'https://cdn.bootcdn.net/ajax/libs/react/17.0.2/umd/react.production.min.js',
            'https://cdn.bootcdn.net/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js',
            'https://cdn.bootcdn.net/ajax/libs/redux/4.1.0/redux.min.js'
          ],
          css: []
        }
      })
      const { isFound, match } = getPlugin(
        webpackConfig,
        pluginByName('HtmlWebpackPlugin')
      )
      if (isFound) {
        // 找到了html的插件
        match.options.cdn = cdn
      }
      return webpackConfig
    }
  }
}

复制代码

在public文件夹中index.html中引入相应文件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />

    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
 
    <title>React App</title>
    <% htmlWebpackPlugin.options.cdn.css.forEach(cdnURL => { %>
      <link rel="stylesheet" href="<%= cdnURL %>"></link>
    <% }) %>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
   
    <% htmlWebpackPlugin.options.cdn.js.forEach(cdnURL => { %>
      <script src="<%= cdnURL %>"></script>
    <% }) %>
  </body>
</html>

复制代码

猜你喜欢

转载自juejin.im/post/7032992615985315871