基于react-app、TS、webpack4一步步搭建可生产的react框架****demo有详细翻译注释说明****

915 阅读6分钟

文章供未搭建过生产环境框架的朋友学习,不严谨处望大佬指正

Hello 小伙伴们,首先问一下你们有自己搭过react框架嘛?

demo地址:https://github.com/babybrotherzb/React-Hook

我好像听到了你们说:of course, react-app 是的说到搭建框架,现在基本都是用的脚手架,简单、快速、高效的脚手架提供给我们的只是通常最基础的一些配套设备,对于我们自己写写demo的话甚至不需要对脚手架进行改动,也就更不会改webpack的配套文件了。 然而 但如果应用到生产环境,我们需要自定义配置一些webpack的功能的话,脚手架提供的显然就不够了,这时候我们就该考虑对脚手架里的webpack "开刀" 了,接下看我们就来对webpack做一场 "手术"。

第一步搭建react-app

现在市面上的脚手架有好几种 我用官网推荐的最新脚手架一行代码搞定

npm init react-app my-app   //npm
yarn create react-app my-app   //yarn

想使用TypeScript进行开发的话,直接基于antd的ts脚手架就行,项目结构都是一样的,webpack文件里已经做好了兼容ts,直接使用就行,

yarn create react-app antd-demo-ts --template typescript

安装好之后项目目录结构就是这样

在这里插入图片描述
安装的TS的话会自动生产一个tsconfig.json配置文件,以及src目录下的react-app-env.d.ts文件用来声明全局的命名空间或者模块,具体的使用可以看typescript官方文档

剥离react-scripts文件

细心的小伙伴会发现,package.json配置文件里的包很少,运行命令都是react-scripts开头,那么我们就去node_modules里找找这个react-script文件,看看它究竟是何方神圣。

在这里插入图片描述
终于耗费我一个月时间终于找到了它,react-scripts包,它核心的两个文件我已经展开了,一个是config配置文件,一个是scripts脚本文件,我们要做的就是把他剥离出去,方便我们后面搞事情,加入我们自己的想法。 ==剩下的我们交给ctrl+c 和 ctrl+v==
在这里插入图片描述
由于这两个文件被剥离出来,我们命令就不能引用react-scripts里的脚本,而是我们剥离后的,所以package.json也得跟着修改

package.json依赖跟着改

在这里插入图片描述
test和eject都是部署自动化测试的我们先不看,只留下打包和运行,习惯vue的dev命令小伙伴还可以加个dev命令,然后我们运行一下
在这里插入图片描述
哦吼,报错了,什么原因呢,原来是我们把两文件拿出来, 相关的依赖没有安装,于是我们去react-scripts里的package.json里,把dependencies里需要的依赖复制出来放到最外面的package.json里 执行命令,安装一波依赖包,二选一

npm install  
yarn install

我们再次运行一下看看 yarn dev

在这里插入图片描述
嗯我们熟悉的它又回来了,严谨点我们再执行yarn build
在这里插入图片描述
到这里说明我们剥离阶段已经完成,这样还不能用于生产,接下来我们在config和scripts文件做写文章,顺带着解读整个webpack

生产分环境打包应用场景

正常开发项目,在发布正式之前,一般都会有个测试环境,如果我们只打一个包用于正式和测试使用,有时候就会很尴尬,尤其是公司配置了自动发布的时候,并不知道你这个包是想发布正式还测试,这时候能按照我需求能分别打包出正式和测试包就很nice了 目标:根据命令行打包出正式或者测试两种包 思考:一个命令要想打出两个包,说明webpack出口文件肯定得有两个

行动一、那我们就找到webpack.config.js文件,找到output

++++++++++++++ 你们安装的项目注释都是英文的,我的demo里把整个webpack和脚本文件都翻译注释了一波 ,为我的辛苦点个star吧 ++++++++++++++ demo地址:https://github.com/babybrotherzb/React-Hook

在这里插入图片描述
这里的出口文件是paths.appBuild的,我们继续找paths这个变量
在这里插入图片描述
发现是一个引用,找到我们去看看这个paths文件

行动二、我们继续找paths.js

在这里插入图片描述
顾名思义,这个文件就是所有打包编译路径文件,这里的appBuild就是打包文件名可以自由配置,那么我们就在build目录下进行判断再生成两个环境的包 思考:我们想搞事情的话就只能在,paths和output之间 因为变量是可以更改的,所以我们重新回到webpack.config.js,对paths进行处理

行动三、回到wabpack修改一波paths

在这里插入图片描述
我们可以看到整个webpack.config.js导出时候接受了一个环境变量,这不正是我们需要的吗,那我们paths.appBuild = build/动态环境变量,是不是就能根据环境生成两个文件夹了
在这里插入图片描述
做好这些,剩下的问题就是webpackEnv是从哪来的?在哪传参的?

行动四、找到webpack方法引用和传参

找啊找,又用一个月终于在,scripts/build.js找到了webpack引用

在这里插入图片描述
这里就是环境变量的传参了,可以看到原来这里写死了
在这里插入图片描述
思考:只要我们能动态的传递环境变量,就能根据变量生成不同的包

行动五、动态添加环境变量

那就给大家推荐一个包 ” inquirer “:https://www.npmjs.com/package/inquirer 然后一波操作

在这里插入图片描述

行动六、打包试试结果如何

我们来试试yarn build,输入打包命令时候手动选择环境

在这里插入图片描述
这不就是我们想要的吗,选择测试和正式分别打包试试
在这里插入图片描述
嗯哼,完美!

优化—打包时生成带CDN链接的index.html

项目中为了提升用户体验,少不了使用cdn

方法一、使用模板引擎+node,动态引入打包好的文件路径

模板引擎哪家强:之前写的文章,这里就不做多介绍了

在这里插入图片描述
但这样还需要单独开启一个node服务,将所有路由都过滤一次统一走模板引擎,在不做SEO的情况下太浪费

方法二、webpack的插件'html-webpack-plugin'、'webpack-manifest-plugin'了解一下

感兴趣的可以去深入研究一下

在这里插入图片描述
在这里插入图片描述
这两个插件,会自动生成一个'asset-manifest.json'文件,将打包的文件路径都存在里面,并动态的生成html标签, 使用cdn的话,打包后上传打包文件,publicPath:cdn路径前缀就可以了

优化—打包时上传静态资源

上传操作,直接写在build.js的打包结束后执行

 //config = await configFactory( env)
 config = await configFactory( env, `${Domain}${Const.projectName}` );

之前这个方法我们传了一个env给webpack,上传静态资源后我们可以将cdn前缀传过去,'webpack-manifest-plugin'当成这个插件的publicPath:路径

 //模拟上传操作
  //************上传操作可以在这里写************* */
  await startUploadImage( env, 'token', 'qiniu' )
  await startUpload( env, 'token', 'qiniu' )
  //************上传操作可以在这里写************* */


/**
 * @desc 上传静态js/css资源
 * @param {string} env 环境变量
 * @param {string} token
 *
 */
async function startUpload( env, token, qiniu ) {

  const files = glob.sync( `${paths.appBuild}/static/{js,css}/**/*.{js,css}` )

  if ( files.length === 0 ) throw new Error( '请先build环境静态资源' )

  for ( let filepath of files ) {
    const fileExtension = filepath.substring( filepath.lastIndexOf( '.' ) + 1 )

    // 文件上传
    console.log( colors.underline( filepath ) )
    console.log( colors.magenta( `${ Const["domain"][env]+'static/'+fileExtension +'/'+ path.basename(filepath)}` ) )
  }
}

/**
 * @desc 上传静态图片资源
 * @param {string} env
 * @param {string} token
 *
 */
async function startUploadImage( env, token, qiniu ) {
  const files = glob.sync( `${paths.appBuild}/static/media/**/*.{png,jpg,gif,jpeg,svg}` )

  for ( let filepath of files ) {
    // 文件上传
    console.log( colors.underline( filepath ) )
    console.log( colors.magenta( `${ Const["domain"][env]+'static/media/' + path.basename(filepath)}` ) )
  }
}

yarn build 看下执行效果

在这里插入图片描述

++++++++++++++ 你们安装的项目注释都是英文的,我的demo里把整个webpack和脚本文件都翻译注释了一波 ,为我的辛苦点个star吧 ++++++++++++++

demo地址:https://github.com/babybrotherzb/React-Hook