react打包后图片丢失_手搭一个 React,Typescript,Koa,GraphQL 环境

33c37b24d5183b317ed61f7e4190ec04.png
本文系原创,转载请附带作者信息:yhlben
项目地址:https://github.com/yhlben/cdfang-spider

前言

在实际的开发过程中,从零开始初始化一个项目往往很麻烦,所以各种各样的脚手架工具应运而生。crea-react-app,vue-cli,@angular/cli 等脚手架工具,只需要执行一个命令,项目结构以及开发环境就搭建好了。

脚手架工具确实方便了我们使用,开发者可以专注于业务,而不需要考虑太多的环境搭建。但作者认为,学习脚手架工具背后的搭建过程也是很重要的,以防脚手架挂了之后,我们还能正常搭建项目。基于这个目的,作者从零搭建了cdfang-spider项目。

现在让我们就以这个项目为例,从零开始搭建项目吧。

项目选型

  1. 三大框架里选哪个?
  2. react 个人爱好。
  3. react-router 定义路由。
  4. react context 状态管理。
  5. react hooks 组件化。
  6. 引入强类型语言?
  7. typescript。为 js 提供类型支持,编辑器友好,增加代码可维护性,使用起来心里踏实。
  8. 在使用第三方库时,可以写出更加符合规范的代码,避免 api 乱用等。
  9. 项目中依赖了大量 @types/xxx 包,无形中增加了项目体积。
  10. 编辑器对 ts 文件进行类型检查,需要遍历 node_modules 目录下所有的 @types 文件,会造成编辑器卡顿现象。
  11. 目前仍然存在很多库没有 @types 支持,使用起来并不方便。
  12. css 选型?
  13. 预编译器 less。项目中使用了变量定义,选择器嵌套,选择器复用等,less 够用了。
  14. 解决命名冲突可以使用 css modules,暂未考虑 css in js。
  15. 使用 bem 命名规范。
  16. 使用 postcss 插件 autoprefixer,增加 css 兼容性。
  17. 构建工具选哪个?
  18. webpack。内置 tree shaking,scope hosting 等,打包效率高,社区活跃。
  19. webpack-merge 合并不同环境配置文件。
  20. 配置 externals。引入 cdn 代替 node_modules 中体积较大的包。
  21. gulp。用来打包 node 端代码。
  22. 代码规范检查?
  23. eslint。辅助编码规范执行,有效控制代码质量。同时也支持校验 typescript 语法。
  24. 配置 eslint-config-airbnb 规则。
  25. 配置 eslint-config-prettier 关闭和 prettier 冲突的规则。
  26. 测试框架选型?
  27. jest。大而全,包含:测试框架,断言库,mock 数据,覆盖率等。
  28. enzyme。测试 react 组件。
  29. 后端框架选型?
  30. koa。精简好用,中间件机制强大。
  31. apollo-server。帮助搭建 graphQL 后端环境。
  32. 数据库选型?
  33. mongodb。类 json 的存错格式,方便存储,前端友好。
  34. 配置 mongoose,方便给 mongodb 数据库建模。
  35. 接口方式选型?
  36. graphql。可以根据需要格式获取对应数据,减少接口冗余数据。
  37. graphql schema 定义了后端接口的参数,操作和返回类型,从此不需要提供接口文档。
  38. 前端可以在 schema 定义后开始开发,数据格式自己掌握。
  39. schema 可拼接。可以组合和连接多个 graphql api,进行级联查询等。
  40. 社区友好,有很多优秀的库可以直接使用: apollo,relay 等。

基本框架选型完毕,接下来就开始搭建项目环境。

搭建 TypeScript 环境

TypeScript 是 JavaScript 的超集,意味着可以完全兼容 JavaScript 文件,但 TypeScript 文件却并不能直接在浏览器中运行,需要经过编译生成 JavaScript 文件后才能运行。

1、 新建 tsconfig.json 文件。

  • tsc -init 生成初始化 tsconfig.json 文件。
  • vscode 会根据 tsconfig.json 文件,进行动态类型检查,语法错误提示等。
  • tsc 命令会根据 tsconfig.json 文件配置的规则,将 ts 代码转换为 js 代码。
  • tslint 会读取 tsconfig.json 文件中的规则,辅助编码规范校验。
  • tslint 官宣会被废弃,后将被 eslint 代替。
  • eslint 同样会用到 tsconfig.json 文件中的内容。

2、 配置 eslint。

根据 typescript-eslint 引导,配置 eslint 对 typescript 的支持。

  • @typescript-eslint/parser 解析 ts 语法。
  • @typescript-eslint/eslint-plugin 为 ts 文件应用 eslint 和 tslint 规则。

3、 选择一个 typescript 编译器,tsc 还是 babel?

使用 babel。好处如下:

  • babel 社区有许多非常好的插件,babel-preset-env 可以支持到具体兼容浏览器的版本号,而 tsc 编译器没这个功能。
  • babel 可以同时支持编译 js 和 ts,所以没必要在引入 tsc 编译 ts 文件,只管理一个编译器,可维护性更高。
  • babel 编译速度更快。tsc 编译器需要遍历所有类型定义文件(*.d.ts),包括 node_modules 里的,以确保代码中正确地使用,type 太多会造成卡顿。
babel 流程分析
babel 是一个 js 语法编译器,在编译时分为 3 个阶段:解析、转换、输出。
  • 解析阶段:将 js 代码解析为抽象语法树(ast)。
  • 转换阶段:对 ast 进行修改,产生一个转换后的 ast。
  • 输出阶段:将转换后的 ast 输出成 js 文件。

plugin 和 preset

  • plugin: 解析,转换,并输出转换后的 js 文件。例如:@babel/plugin-proposal-object-rest-spread 会输出支持{...}解构语法的 js 文件。
  • preset: 是一组组合好的 plugin 集合。例如:@babel/preset-env 让代码支持最新的 es 语法,自动引入需要支持新特性的 plugin。

4、搜集所有的 ts,tsx 页面(前端环境使用 webpack,node 项目使用 gulp),然后通过 babel 编译成 js 文件。

搭建 React 环境

React 是一个库,基于组件式开发,开发时常常需要用到以下语法:

  • es6 模块化。
  • jsx 语法。
  • typescript 语法。
  • css 预处理器。

这些语法在目前浏览器中并不能直接执行,需要进行打包编译,这也是搭建 React 环境的主要工作。

具体步骤

1、新建一个 html 文件,并在 body 中创建一个根节点,用于挂载 react 最后生成的 dom。

2、新建一个 index.tsx 文件,用于将项目中的所有组件,引入进来,并调用 render 方法,将组件渲染到根节点中。

3、React 项目分层。

  • containers 目录,存放单独的页面
  • components 目录,存放的是组件,一个组件包含 jsx 和 css 两个部分。
  • context 目录,存放公用的 react context。
  • config 目录,存放公共配置文件。
  • utils 目录,公用的函数组件库。
  • constants 目录,存放静态变量。

4、配置 webpack,以 index.tsx 为入口文件,进行打包编译。

  • 由于不同环境的打包方式并不相同,这里抽象出开发环境、上线环境、优化环境的配置文件,使用 webpack-merge 合并配置文件。
  • 配置 css 预处理器,使用 less-loader。
  • 配置 ts 编译器,使用 babel-loader。
  • @babel/preset-env:编译最新的 es 语法。
  • @babel/preset-react:编译 react 语法。
  • @babel/preset-typescript:转换 typescript 语法。
  • 配置 url-loader,打包项目中的图片资源。
  • 配置 html-webpack-plugin 将最后生成的 js,css,注入第 1 步的 html 中。
  • 使用 ejs 模板配置开发环境和线上环境引入的 cdn。
  • 开发环境配置,使用开箱即用的 webpack-dev-server。
  • webpack-dev-server 可以自动监听文件修改,自动刷新页面,以及默认 source-map 等功能。
  • 配置热模块替换,react-hot-loader。
webpack 打包原理
webpack 打包过程就像是一条流水线,从入口文件开始,搜集项目中所有文件的依赖关系,如果遇到不能够识别的模块,就使用对应的 loader 转换成能够识别的模块。webpack 还能使用 plugin 在流水线生命周期中挂载自定义事件,来控制 webpack 输出结果。

5、编写 npm script,一键开启开发模式。

// cross-env 用来跨环境设置环境变量
"scripts": {"dev:client": "cross-env NODE_ENV=development webpack-dev-server --open"
}

6、现在运行 npm run dev:client 就可以愉快地编写客户端代码了。

搭建 NodeJs 环境

由于 node 端使用了 typescript 和最新的 es 语法,所以需要进行打包编译。

  • 配置 gulp,遍历每一个 ts 文件,调用 gulp-babel,将 ts 代码转换成 js 代码。
  • 配置 supervisor 自动重启 node 服务(nodemon 对于不存在的目录不能进行监控)。
  • 编写 npm script 一键启动 node 端开发环境。
"scripts": {"dev:server": "cross-env NODE_ENV=development gulp & cross-env NODE_ENV=development supervisor -i ./dist/client/ -w ./dist/ ./dist/app.js",
}

配置好 gulp 后,就可以运行 npm run dev:server 一键启动服务器端开发环境。

层次结构划分

项目采用传统的 mvc 模式进行层次划分。

Model 层

Model 层的主要工作:连接数据库,封装数据库操作,例如:新增数据、删除数据、查询数据、更新数据等。

  • 新建 model 文件夹,目录下的每一个文件对应数据库的一个表。
  • model 文件中包含对一个数据表的增删改查操作。
  • 使用 mongoose 更方便地对 mongodb 数据库进行读写操作。
  • model 文件返回封装好的对象,提供给 controller 层使用。

Controller 层

Controller 层的主要工作:接收和发送 http 请求。根据前端请求,调用 model 层获取数据,再返回给前端。

传统的后端一般还包含 service 层,专门用来处理业务逻辑。
  • 根据前端请求,找到对应的 model 层获取数据,经过加工处理后,返回给前端。
  • 编写中间件,记录系统日志,错误处理,404 页面等。
  • 支持前端 react-router 中的 BrowserRouter。根据前端路由,后端配置对应的路由,匹配结果为 index.html 文件。
  • 项目中使用的 graphql 比较基础,也直接放在了 controller 层进行处理。

View 层

View 层的主要工作:提供前端页面模板。如果是服务器端渲染,是将 model 层的数据注入到 view 层中,最后通过 controller 层返回给客户端。由于本项目前端使用 react 渲染,所以 view 层直接是经过 webpack 打包后的页面。

  • 使用 koa-static 提供一个静态文件服务器,用来访问前端打包后生成的 html 文件。

搭建 GraphQL 环境

GraphQL 是一种用于 api 的查询语言,需要服务器端配置 graphql 支持,同时也需要客户端使用 graphql 语法的格式进行请求。

使用 apollo 更快的搭建 graphql 环境。

  • 服务器端配置 apollo-server。
  • 使用 schema,定义请求的类型,返回的格式。
  • 使用 resolvers 来处理对应的 schema。
  • 客户端配置 apollo-client。
  • 按照 apollo-server 定义的 schema,来请求数据。

搭建 MongoDB 环境

MongoDB 是一个面向文档存储的数据库,操作起来十分简单。

Mongoose 为 mongodb 提供了一种直接的,基于 scheme 结构去定义你的数据模型。它内置数据验证,查询构建,业务逻辑钩子等,开箱即用。

  • 使用 mongoose 建立和本地 mongodb 的连接。
  • 创建 model 模型,一个模型对应 mongodb 里的一张表。
  • 根据 model 封装增删改查功能,并返回给 controller 层使用。

接下来的步骤就是安装 mongodb,启动服务,就可以了。

搭建测试环境

本项目使用 jest 作为测试框架,jest 包含了断言库、测试框架、mock 数据等功能,是一个大而全的测试库。由于前端使用了 react 项目,这里引入了专门用来测试 react 的 enzyme 库。

1、新建 jest.config.js 文件。

  • 配置初始化 setup.ts 文件。
  • 根据 react 版本配置对应的 enzyme-adapter。
  • mock 全局变量,如 fech,canvas 等。
  • 配置需要测试的文件。
  • 配置 mock 数据文件。
  • 配置测试文件的编译方式。
  • ts 代码使用 ts-jest 编译。
  • 配置代码覆盖率文件。

2、编写测试文件。

  • 新建__mocks__,__tests__目录,存放测试文件和 mock 数据文件。
  • 按照 src 中的目录,建立相应的测试文件目录。

3、编写测试脚本和上传覆盖率脚本。

"scripts": {"test": "jest --no-cache --colors --coverage --forceExit --detectOpenHandles","coverage": "codecov"
}

配置上线环境

安装好各种环境之后,接下来就要考虑项目上线了。

配置服务器环境

  • 安装 nodejs 环境。nvm 安装 node
  • 安装 pm2 进程守护。npm i pm2 -g
  • 安装 mongodb。mongodb 官方文档
  • 安装免费 https 证书。letsencrypt 官网
  • 域名需要先进行备案(使用阿里云备案,资料准备齐全的话 10 天左右就可以批下来)。

代码发布

本项目发布非常简单,只需要一步操作就搞定了,这些都是经过持续集成配置后的结果。

# clone with Git Bash
git clone https://github.com/yhlben/cdfang-spider.git# change directory
cd cdfang-spider# install dependencies
npm i# build for production with minification
npm run build

所有的事情都在 build 命令下完成了,我们分析一下 npm run build 命令做的事情。

  • eslint 语法错误检查。
  • 单元测试。
  • 上传测试覆盖率。
  • 打包客户端代码。
  • 打包后生成 html 文件作为 node 端的 view 层,和后端绑定在一起。
  • 其他静态资源,在 webpack 打包后自动上传到七牛 cdn,使用 qiniu-upload-plugin 来进行一键上传。
  • 打包服务器端代码。

上述事情通过创建 npm script 就可以了完成需求了,但这些命令也不应该每次都由手工敲一遍,通过配置 travisCI,每一次 master 分支提交代码时,自动运行上述命令就行了。

travisCI 配置

travisCI 是一个持续集成平台,每当 github 提交代码时,travisCI 就会得到通知,然后根据 travisCI 中的配置信息执行相应的操作,并及时把运行结果反馈给用户。travisCI 配置文件可以参考项目根目录下的 .travis.yml 文件。配置文件核心在于 script 的配置。

script:- npm run build- npm run test
after_success: npm run coverage

可以看到,每一次 github 提交后,travisCI 就会执行 名称为 build 的任务,任务分为 2 个步骤,首先执行 build 命令,然后执行 test 命令,当命令都执行完成后,执行 coverage 命令。如果执行命令期间出现任何错误,travisCI 会通过邮件及时通知我们。真正要上线时,先查看 ci 状态,如果已通过所有的步骤,那就不用担心发布的代码有问题了。

总结

至此,整个项目选型与搭建流程已经介绍完毕了,当然还有一些很细节的地方没有写进去,如果有不太明白的地方,可以提 issue,或者加我微信 yhl2016226。

接下来对以下 4 个方面写个小总结。

  • 开发方面:项目将前端、后端、数据库端连通起来,组合成了一个小全栈的项目,加深了我对整个开发环节的理解。
  • 测试方面:通过编写单元测试,ui 测试,api 测试,积累了自动化测试方面的经验。
  • 运维方面:通过配置持续集成,守护进程,nginx,https 等,让我有能力实现小型项目的部署。
  • 技术方面:项目中使用了一些比较新的技术,如:hooks api,graphql 等,但用的都很基础,主要是为了练手,后续还得深入学习。

对于项目后期更新,主要是基于以下几个方面:graphql,docker,k8s,微服务,serverless 等,东西太多,还得加油学习啊,

参考链接

  • TypeScript 和 Babel
  • 前端决策树

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/366057.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无需改动现有网络,企业高速远程访问内网Linux服务器

某企业为数据治理工具盒厂商,帮助客户摆脱数据问题困扰、轻松使用数据,使得客户可以把更多精力投入至数据应用及业务赋能,让数据充分发挥其作为生产要素的作用。 目前,该企业在北京、南京、西安、武汉等地均设有产研中心&#xff…

使用Hazelcast发布和订阅

几周前,我写了一篇有关Hazelcast入门的博客,描述了创建分布式地图,列表和队列是多么简单。 当时我提到Hazelcast还能做很多其他事情。 该博客快速浏览了Hazelcast的另一个功能:基于Publish / Subscribe模式的广播消息系统。 这采用…

接口自动化测试持续集成--Soapui接口功能测试参数化

按照自动化测试分层实现的原理,每一层的脚本实现都要进行参数化,自动化的目标就是要实现脚本代码与测试数据分离。当测试数据进行调整的时候不会对脚本的实现带来震荡,从而提高脚本的稳定性与灵活度,降低脚本的维护成本。Soapui最…

Codeforces 1027E Inverse Coloring 【DP】

Codeforces 1027E Inverse Coloring 题目链接 1 #include<bits/stdc.h>2 using namespace std;3 #define N 10104 #define LL long long5 #define Mod 9982443536 int n,k;7 LL dp[N][N],ans0;8 LL sum[N][N];9 int main(){ 10 cin>>n>>k; 11 dp[0][…

合并远程仓库到本地_git远程仓库创建和合并

上周发了一个张佳波小朋友关于git的文章&#xff0c;马上就更多小朋友的回馈。其中周玉涛同志发来了自己对于git之前问题的一些理解和解决方法&#xff0c;希望能帮助更多人解决问题。为了保证周玉涛同学提供材料的完整性&#xff0c;以下将他原文和图片发出&#xff0c;不做其…

swfobject.js视频播放插件

在网页中经常会用到视频播放的功能&#xff0c;下面介绍一下swfobject.js的视频播放应用&#xff1a;html代码结构&#xff1a; <div id"video_content"></div> css样式结构&#xff1a; body{background: #003368}#video_content{width:600px;height:40…

Spring REST:异常处理卷。 3

这是该系列中有关Spring REST异常处理的最后一篇文章。 最后&#xff0c;这次我将讨论在表单处理期间可能发生的REST异常的处理。 因此&#xff0c;在本教程中&#xff0c;您将看到与REST&#xff0c;表单和异常处理有关的所有内容。 客户端呢&#xff1f; jQuery将用于反映RES…

centos6安装mysql并远程连接_Ubantu下MySQL安装、部署和远程连接

系统阿里云 ubantu 16.04MySQL 5.0/8.0连接工具 Navicat Premium安装MySQL1、MySQL 5.0直接使用apt命令安装sudo apt install mysql-server输入密码完成安装。安装完mysql-server后&#xff0c;mysql-client就带了&#xff0c;无需单独安装安装成功后输入如下命令检查数据库状态…

js中字符串和数组的使用

函数&#xff1a; 函数在调用的时候&#xff0c;会形成一个私有作用域&#xff0c;内部的变量不会被外面访问&#xff0c;这种保护机制叫闭包。这就意味着函数调用完毕&#xff0c;这个函数形成的栈内存会被销毁。 但有时候我们不希望他被销毁。 函数归属谁跟它在哪调用没有关…

Spring REST:异常处理卷。 1个

目录 Spring REST&#xff1a;异常处理卷。 1个 Spring REST&#xff1a;异常处理卷。 2 Spring REST&#xff1a;异常处理卷。 3 大家好&#xff0c;是时候继续在我的博客中发布新文章了。 因此&#xff0c;我很高兴地宣布&#xff0c;我计划编写一系列技术文章。 在当前文…

vue/cli3 配置vux

安装各插件 试过 安装“必须安装”的部分亦可 1、安装vuex npm install vuex --save-dev 2、在项目里面安装vux【必须安装】 npm install vux --save 3、安装vux-loader【必须安装】 npm install vux-loader --save-dev 4、安装less-loader&#xff08;这个是用以正确编译less源…

鼠标右键 移动选定的文件夹到指定位置_怎么把电脑桌面上的文件移动到更加安全的地方...

我们在使用电脑的时候习惯于把各种文档以及其他文件资料随手保存到电脑桌面上&#xff0c;这样操作可以方便以后对这些文档和文件资料的使用、管理&#xff0c;但是由于默认状态下桌面文件位于C盘中&#xff0c;这些文件资料不仅会占用掉C盘的很大的存储空间&#xff0c;并且日…

非常精简的Linux线程池实现(一)——使用互斥锁和条件变量

线程池的含义跟它的名字一样&#xff0c;就是一个由许多线程组成的池子。 有了线程池&#xff0c;在程序中使用多线程变得简单。我们不用再自己去操心线程的创建、撤销、管理问题&#xff0c;有什么要消耗大量CPU时间的任务通通直接扔到线程池里就好了&#xff0c;然后我们的主…

嵌入式linux系统文件,嵌入式Linux文件系统知多少

Nand/Nor Flash在嵌入式Linux产品中&#xff0c;通常使用的存储介质为Nand Flash和Nor Flash&#xff0c;而手机、相机等产品通常使用eMMC、SD Card作为存储介质&#xff0c;导致这种差异的原因主要是成本考量。Nand Flash和Nor Flash具有低成本、高密度存储的优势。但是&#…

三分钟上手Highcharts简易甘特图

根据业务需求&#xff0c;找到了这个很少使用的图形&#xff0c;话不多说&#xff0c;看看该如何使用。首先要引入支持文件&#xff1a;可根据链接下载。 exporting.js&#xff1a;https://img.hcharts.cn/highcharts/modules/exporting.js xrange.js&#xff1a;https://img.h…

WEB语义化

WEB语义化让机器读懂内容&#xff0c;HTML就带有一定「语义」的标签&#xff0c;比如段落&#xff0c;标题&#xff0c;表格和图片等。让机器读懂内容&#xff0c;那么两种方案&#xff1a;第一种让机器变得更人工智能化&#xff0c;也就是现在大火的AI。第二种是人们去发布认可…

关于使用JQ scrollTop方法进行滚动定位

没图我说个锤子&#xff0c;先来个自拍镇楼。 又到了每周周五总结时间。我广州刘德华又来讲故事了。这一周没啥任务&#xff0c;就一个任务&#xff0c;产品口头交代了两句&#xff0c;也没有psd没有设计图没有样式。自由发挥&#xff0c;你自己敲代码做个作品出来。 what&…

ssh密钥登录

方法一:使用下例中ssky-keygen和ssh-copy-id&#xff0c;仅需通过3个步骤的简单设置而无需输入密码就能登录远程Linux主机。 ssh-keygen 创建公钥和密钥。 ssh-copy-id 把本地主机的公钥复制到远程主机的authorized_keys文件上。ssh-copy-id 也会给远程主机的用户主目录&#x…

Spring REST:异常处理卷。 2

这是有关使用Spring进行REST异常处理的系列的第二篇文章。 在我以前的文章中&#xff0c;我描述了如何在REST服务中组织最简单的异常处理。 这次&#xff0c;我将更进一步&#xff0c;我将向您展示何时最好在ControllerAdvice级别上使用异常处理 。 介绍 在开始本文的技术部分…

python 装饰器有哪些_python装饰器有什么用

简言之&#xff0c;python装饰器就是用于拓展原来函数功能的一种函数&#xff0c;这个函数的特殊之处在于它的返回值也是一个函数&#xff0c;使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。 一般而言&#xff0c;我们要想拓展原来函数代码&…