vlambda博客
学习文章列表

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

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

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

我好像听到了你们说:of course, react-app

是的说到搭建框架,现在基本都是用的脚手架,简单、快速、高效的脚手架提供给我们的只是通常最基础的一些配套设备,对于我们自己写写demo的话甚至不需要对脚手架进行改动,也就更不会改webpack的配套文件了。

然而

但如果应用到生产环境,我们需要自定义配置一些webpack的功能的话,脚手架提供的显然就不够了,这时候我们就该考虑对脚手架里的webpack "开刀" 了,接下看我们就来对webpack做一场 "手术"。

第一步搭建react-app

现在市面上的脚手架有好几种

我用官网推荐的最新脚手架一行代码搞定

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

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


剥离react-scripts文件

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

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

剩下的我们交给ctrl+c 和 ctrl+v


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

由于这两个文件被剥离出来,我们命令就不能引用react-scripts里的脚本,而是我们剥离后的,所以package.json也得跟着修改


package.json依赖跟着改


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

test和eject都是部署自动化测试的我们先不看,只留下打包和运行,习惯vue的dev命令小伙伴还可以加个dev命令,然后我们运行一下


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

哦吼,报错了,什么原因呢,原来是我们把两文件拿出来, 相关的依赖没有安装,于是我们去react-scripts里的package.json里,把dependencies里需要的依赖复制出来放到最外面的package.json里

执行命令,安装一波依赖包,二选一

npm install yarn install

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


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

嗯我们熟悉的它又回来了,严谨点我们再执行yarn build


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

到这里说明我们剥离阶段已经完成,这样还不能用于生产,接下来我们在config和scripts文件做写文章,顺带着解读整个webpack


生产分环境打包应用场景

正常开发项目,在发布正式之前,一般都会有个测试环境,如果我们只打一个包用于正式和测试使用,有时候就会很尴尬,尤其是公司配置了自动发布的时候,并不知道你这个包是想发布正式还测试,这时候能按照我需求能分别打包出正式和测试包就很nice了,

目标:根据命令行打包出正式或者测试两种包

思考:一个命令要想打出两个包,说明webpack出口文件肯定得有两个


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


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

这里的出口文件是paths.appBuild的,我们继续找paths这个变量


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

发现是一个引用,找到我们去看看这个paths文件


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

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

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


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

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

我们可以看到整个webpack.config.js导出时候接受了一个环境变量,这不正是我们需要的吗,那我们paths.appBuild = build/动态环境变量,是不是就能根据环境生成两个文件夹了


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

做好这些,剩下的问题就是webpackEnv是从哪来的?在哪传参的?


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

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

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

这里就是环境变量的传参了,可以看到原来这里写死了

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

思考:只要我们能动态的传递环境变量,就能根据变量生成不同的包


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

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


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

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

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

这不就是我们想要的吗,选择测试和正式分别打包试试

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

嗯哼,完美!


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

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

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

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

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


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

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

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



这两个插件,会自动生成一个'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 看下执行效果



CSDN博客  、 掘金 ,搜索:@baby张  更多专栏技术文章