react技术揭秘脚本之家 (react开发遇到的难点和解决方法)

今天想要分享的是“ 黑盒 ”。

最近,在搭建某个业务系统的过程中,我选用了 react 作为主要的技术栈。和同事的业务交流中,我提到了“黑盒”这个词汇。

在我司同事的强烈要求(火锅承诺)下,就有了今天这篇《CRA 为什么要做成“黑盒”》。

# 什么是“黑盒”

首先从前端 er 们熟悉的 vue-cli 说起,以下是vue 脚手架的基本目录:

React技术栈详解学习,react技术栈入门篇

再来看下 create-react-app 的项目目录:

React技术栈详解学习,react技术栈入门篇

在这里,我就不对每个文件进行介绍了。

相比 create-react-app,vue-cli 将配置文件完全暴露出来。但是,create-react-app 的基本目录中却隐藏了 config 相关的配置文件,当然 @vue/cli 也做了相关功能的实现。

对于这种方式我把它称之为“ 黑盒 ”,也就是我们今天的主题。

# 脚手架为什么要使用黑盒

一般的项目流程大致如下所示:

  • 实现项目的基本结构,如基础设置搭建,测试;
  • 过程中的文件配置,如 webpack eslint 等;
  • 完成项目业务的一些功能需求。

在实际业务操作中,前面两项流程可以为后期的项目服务,进而减少很多重复性的工作。

所以,为了开发的方便性,我们完全可以用一个 黑盒子 把项目的基本架构和文件配置装起来,给后续开发者们留下一些“痕迹”,这样新手们就不需要担心项目的前期准备,达现开箱即用的体验。

React技术栈详解学习,react技术栈入门篇

开箱即用是给开发者提供的一种便利。

# 矛盾的黑盒自由

开发界有这样一条箴言:“新手渴望规则,老手渴望自由”。

随着开发者能力的提升,黑盒可能无法满足你的需求,娴熟的老手们越来越想解除黑盒的约束,都想去实现黑盒中文件的自由支配,但 @vue/cli 和 create-react-app 黑盒给老手们的自由度是完全不一样的。

  • @vue/cli 给老手们留了实现黑盒自由的接口 vue-config.js
  • create-react-app 的宗旨是,要么不给自由,要么把自由权全给你 npm run eject

技术大佬们对于 create-react-app 的黑盒是爱恨交加的,既想让它给予自由,又不想打破它的黑盒约束。

黑盒自由一旦被打破,整个操作是不可逆的,项目依赖项后期的版本更新就无人可做了。

所以有技术大佬投身于 CRA 的研究,最终实现了两方面都能兼得的效果,既能保证开发者受制于 CRA 黑盒,又能实现黑盒中文件配置的自由。

React技术栈详解学习,react技术栈入门篇

实现 react 中的 CRA 的依赖项是 react-app-rewired。 地址:https://www.npmjs.com/package/react-app-rewired

React技术栈详解学习,react技术栈入门篇

之前我们聊到,之所以在 Vue 和 React 中实现黑盒功能,其目的很明确,就是方便版本升级后,我们所开发的项目的依赖会自动跟随升级。

但是,一旦打破这种约束,表面上看起来是“我行我素”了,事实上项目变得糟糕透了,项目后期的维护会相当困难。

今天我们就来聊聊如何使得两者兼具,即满足项目依赖自动升级,又能死死地拿捏住黑盒中配置文件的主动权。

# 以 React 中的 CRA 为例

当我们使用 create-react-app 搭建项目的基础结构时,它基本的目录是这样的:

React技术栈详解学习,react技术栈入门篇

在这个目录下,没有找到任何跟 config 有关的文件。

在没有配置文件的情况下,我们来谈一个简单的需求:

  • 项目里要采用 css 预处理器 less || sass

乍一看这个需求很简单,但是却发现整个项目中找不到半点和 webpack.config 相关的文件,有种 “ 狗咬刺猬,无处下嘴 ”的感觉。

React技术栈详解学习,react技术栈入门篇

别担心,本文的主角 react-app-rewired 登场了!它就像是一把手术刀,可以一下子解决病根。

https://www.npmjs.com 官网上搜索 react-app-rewired 的简介:

  • Tweak the create-react-app webpack config(s) without using 'eject' and without creating a fork of the react-scripts. 在不使用 'eject' 且未创建 react-scripts 分支的情况下,调整 create-react-app 中 webpack 配置。
  • All the benefits of create-react-app without the limitations of "no config". You can add plugins, loaders whatever you need. create-react-app 的所有好处没有“ no config”的限制。您可以根据需要添加插件,加载程序。

虽然翻译得非常直白,但依然令人兴奋不已。它真的可以争取 CRA 中 webpack 配置的主动权。

# 动手操作

首先,安装 react-app-rewired 项目目录下 npm install react-app-rewired -S

安装完之后看一下 react-app-rewired 的版本:

React技术栈详解学习,react技术栈入门篇

*载下**完后的版本是 react-app-rewired@2.1.6。

接下来,在当前目录创建一个 config-overrides.js 文件,文件内容如下:

module.exports = function override(config, env) {
  //do stuff with the webpack config...
  return config;
}

最后修改 package.json 中的 scripts 脚本指令,具体流程参考https://github.com/timarney/react-app-rewired

修改前

React技术栈详解学习,react技术栈入门篇

修改后

React技术栈详解学习,react技术栈入门篇

npm start 我们发现项目依然可以正常启动。

React技术栈详解学习,react技术栈入门篇

# 接受 webpack 的配置项

对于修改黑盒内的 webpack 配置,react-app-rewired 2.0+ 版本需要另一个依赖模块叫 customize-cra

npm install customize-cra -S 安装这个依赖。同时安装 less-loader,安装方式 npm install less-loader -D

这是它对外 API 介绍地址:https://github.com/arackaf/customize-cra/blob/master/api.md

const { override,addLessLoader } = require("customize-cra");
module.exports = override(addLessLoader());
//丰富的API可以满足你项目的任何需求

下面演示向配置项中添加 less-loader,然后将 App.css 改成 App.less。同时将 less 文件引入到 App.js 中。

React技术栈详解学习,react技术栈入门篇

npm start 重新启动服务后,页面效果如下:

React技术栈详解学习,react技术栈入门篇

以上就是实现 CRA 黑盒中 webpack.config 文件的关于 less 的自由配置的整个过程。

我们终于把 CRA 的黑盒主动权争取来了!

# CRA 黑盒的实现

不管是 @vue/cli 还是 create-react-app,它们内部都暗藏着黑盒的机制。在这里大家万不可把 @vue/cli 和 create-react-app 都认为是黑盒。它们仅仅是官方提供的两个脚手架,用于快速搭建项目基础结构。

React技术栈详解学习,react技术栈入门篇

# 黑盒如何工作

在项目开发中,我们把它分成三份:一份是是项目结构,一份是黑盒,一份是最终的产出。

React技术栈详解学习,react技术栈入门篇

简单来说,写好后的项目,经过黑盒处理之后,就成了一个可以上线部署的产品。这个处理过程就需要前端开发者们去努力实现了。

黑盒其实很简单,就是需要我们打破平时的开发思维,给开发者提供更简单的解决方案,一句话概括就是怎么简单怎么来。

对于黑盒原理,我个人认为它其实就是 包裹的 webpack 或者其他工具

本篇文章我们就以 webpack 为例,写一个自己的黑盒。

正常使用 webpack 的开发中,我们需要手动创建一个 webpack 的配置文件 webpack.config.js 。

黑盒现在要做的是:

  • 删掉这个配置文件,在内部完成基本配置。
  • 如果你想要自己配置,不好意思,你得按照我的约定来,更换新的配置文件 demo.config.js(demo是自己起的名字)

# 实际操作

有一个已经配置好的项目,如下图:

React技术栈详解学习,react技术栈入门篇

配置文件的内容很简单,如下:

const path = require("path")
module.exports =  {
    mode:"none",
    entry:"./src/index.js",
    output:{
        path:path.resolve(process.cwd(),"dist"),
        filename:"bundle.js"
    }
}

现在我们要移除 webpack.config.js 文件,同时在项目同级目录下建个 cwj-page 的文件夹。

React技术栈详解学习,react技术栈入门篇

这个 cwj-page 就是我们要实现的黑盒。

它里面的文件结构如下:

React技术栈详解学习,react技术栈入门篇

bin 文件夹是我们使用该文件夹名称当作指令要执行的文件,在 bin 文件夹下创建一个跟黑盒同名的 js 文件: cwj-page.js 内容如下:

#!/usr/bin/env node

const config = require("..")
const webpack = require("webpack")
const compiler = webpack(config,(err,state)=>{
    if(err)throw err;
    console.log("编译成功")
})

lib 是我们要存储的一个js文件,这个文件其实就是我们所有关于 webpack.config.js 的基本配置。

const path = require("path")
const cwd = process.cwd()
const fs = require("fs")
let config = {
    mode:"none",
    entry:"./src/index.js",
    output:{
        path:path.resolve(process.cwd(),"dist"),
        filename:"build.js"
    }
}
// const loadconfig = require(`${cwd}/page.config.js`)
let cf = fs.existsSync(`${cwd}/page.config.js`)//判断当前目录下时候有约定的配置文件

if(cf){ //有约定的配置文件
    try {
        const loadconfig = require(`${cwd}/page.config.js`)
        config = Object.assign({},config,loadconfig)
    }catch(e){
        console.log(e)
    }
}else{ //没有约定的配置文件
    onfig = Object.assign({},config)
}

module.exports = config

注意 :在这个 cwj-page 下的 webpack 必须用 npm install webpack -S *载下**,因为它是黑盒所依赖的模块,目的就是要对 webpack 进行包装。

完成之后我们现在要把 cwj-page 发布 npm 或者直接本地软连接,因为我们后面的操作要完全使用黑盒指令对项目打包。所以在 cwj-page 下的终端进行 npm link,这样在全局安装目录下就会有一个 cwj-page 的文件。

React技术栈详解学习,react技术栈入门篇

再回到 demo 项目下,在 src 下的 index.js 随便写写 js 代码 ,然后使用黑盒指令 cwj-page。

React技术栈详解学习,react技术栈入门篇

到此,一个简单的黑盒就算包装成功了。后期我会录制一个实现黑盒的视频,将同步发布 bilibili 和公号上,到时候各位小伙伴们别忘了一键三连!