从 0 到 1 再到 100, 搭建、编写、构建一个前端项目

从 0 到 1 再到 100, 搭建、编写、构建一个前端项目

1. 选择现成的项目模板仍是本身搭建项目骨架

搭建一个前端项目的方式有两种:选择现成的项目模板、本身搭建项目骨架。css

选择一个现成项目模板是搭建一个项目最快的方式,模板已经把基本的骨架都搭建好了,你只须要向里面填充具体的业务代码,就能够经过内置的工具与命令构建代码、部署到服务器等。html

通常来讲,一个现成的项目模板会预约义必定的目录结构、书写方式,在编写项目代码时须要遵循相应的规范;也会内置必要的工具,好比 .editorconfigeslintstylelintprettierhuskylint-staged 等;也会内置必要的命令(package.json | scripts),好比 本地开发:npm run dev本地预览:npm run start构建:npm run build部署:npm run deploy 等。前端

社区比较好的项目模板:vue

这些模板的使用又分为两种:使用 git 直接克隆到本地、使用命令行建立。node

(使用现有模板构建的项目,能够跳过第 2 ~ 7 步)react

1.1 使用 git 直接克隆到本地

这是一种真正意义上的模板,能够直接到模板项目的 github 主页,就能看到整个骨架,好比 react-boilerplateant-design-provue-element-adminreact-starter-kitjquery

react-boilerplate 为例:webpack

克隆到本地:git

git clone --depth=1 https://github.com/react-boilerplate/react-boilerplate.git <你的项目名字>

切换到目录下:es6

cd <你的项目名字>

通常来讲,接下来运行 npm run install 安装项目的依赖后,就能够运行;有些模板可能有内置的初始化命令,好比 react-boilerplate

npm run setup

启动应用:

npm start

这时,就能够在浏览器中预览应用了。

1.2 使用命令行建立

这种方式须要安装相应的命令,而后由命令来建立项目。

create-react-app 为例:

安装命令:

npm install -g create-react-app

建立项目:

create-react-app my-app

运行应用:

cd my-app
npm start

1.3 本身搭建项目骨架

若是你须要定制化,能够选择本身搭建项目的骨架,但这须要开发者对构建工具如 webpacknpmnode 及其生态等有至关的了解与应用,才能完美的把控整个项目。

下面将会一步一步的说明如何搭建一个定制化的项目骨架。

2. 选择合适的规范来写代码

js 模块化的发展大体有这样一个过程 iife => commonjs/amd => es6,而在这几个规范中:

  • iife: js 原生支持,但通常不会直接使用这种规范写代码
  • amd: requirejs 定义的加载规范,但随着构建工具的出现,便通常不会用这种规范写代码
  • commonjs: node 的模块加载规范,通常会用这种规范写 node 程序
  • es6: ECMAScript2015 定义的模块加载规范,须要转码后浏览器才能运行

这里推荐使用 es6 的模块化规范来写代码,而后用工具转换成 es5 的代码,而且 es6 的代码可使用 Tree shaking 功能。

参考:

3. 选择合适的构建工具

对于前端项目来讲,构建工具通常都选用 webpackwebpack 提供了强大的功能和配置化运行。若是你不喜欢复杂的配置,能够尝试 parcel

参考:

4. 肯定是单页面应用(SPA)仍是多页面应用

由于单页面应用与多页面应用在构建的方式上有很大的不一样,因此须要从项目一开始就肯定,使用哪一种模式来构建项目。

4.1 多页面应用

传统多页面是由后端控制一个 url 对应一个 html 文件,页面之间的跳转须要根据后端给出的 url 跳转到新的 html 上。好比:

http://www.example.com/page1 -> path/to/page1.html
http://www.example.com/page2 -> path/to/page2.html
http://www.example.com/page3 -> path/to/page3.html

这种方式的应用,项目里会有多个入口文件,搭建项目的时候就须要对这种多入口模式进行封装。另外,也能够选择一些封装的多入口构建工具,如 lila

4.2 单页面应用

单页面应用(single page application),就是只有一个页面的应用,页面的刷新和内部子页面的跳转彻底由 js 来控制。

通常单页面应用都有如下几个特色:

  • 本地路由,由 js 定义路由、根据路由渲染页面、控制页面的跳转
  • 全部文件只会加载一次,最大限度重用文件,而且极大提高加载速度
  • 按需加载,只有真正使用到页面的时候,才加载相应的文件

这种方式的应用,项目里只有一个入口文件,便无需封装。

参考:

5. 选择合适的前端框架与 UI 库

通常在搭建项目的时候就须要定下前端框架与 UI 库,由于若是后期想更换前端框架和 UI 库,代价是很大的。

比较现代化的前端框架:

一些不错的组合:

参考:

6. 定好目录结构

一个好的目录结构对一个好的项目而言是很是必要的。

一个好的目录结构应当具备如下的一些特色:

  1. 解耦:代码尽可能去耦合,这样代码逻辑清晰,也容易扩展
  2. 分块:按照功能对代码进行分块、分组,并能快捷的添加分块、分组
  3. 编辑器友好:须要更新功能时,能够很快的定位到相关文件,而且这些文件应该是很靠近的,而不至于处处找文件

比较推荐的目录结构:

多页面应用

|-- src/ 源代码目录

    |-- page1/ page1 页面的工做空间(与这个页面相关的文件都放在这个目录下)
        |-- index.html html 入口文件
        |-- index.js js 入口文件
        |-- index.(css|less|scss) 样式入口文件
        |-- html/ html 片断目录
        |-- (css|less|scss)/ 样式文件目录
        |-- mock/ 本地 json 数据模拟
        |-- images/ 图片文件目录
        |-- components/ 组件目录(若是基于 react, vue 等组件化框架)
        |-- ...
        
    |-- sub-dir/ 子目录
        |-- page2/ page2 页面的工做空间(内部结构参考 page1)
            |-- ...
        
    |-- ...
    
|-- html/ 公共 html 片断
|-- less/ 公共 less 目录
|-- components/ 公共组件目录
|-- images/ 公共图片目录
|-- mock/ 公共 api-mock 文件目录
|-- ...

单页面应用

|-- src/ 源代码目录
    |-- page1/ page1 页面的工做空间
        |-- index.js 入口文件
        |-- services/ service 目录
        |-- models/ model 目录
        |-- mock/ 本地 json 数据模拟
        |-- images/ 图片文件目录
        |-- components/ 组件目录(若是基于 react, vue 等组件化框架)
        |-- ...
        
    |-- module1/ 子目录
        |-- page2/ page2 页面的工做空间(内部结构参考 page1)
        
    |-- ...
    
|-- images/ 公共图片目录
|-- mock/ 公共 api-mock 文件目录
|-- components/ 公共组件目录   
|-- ...

参考:

7. 搭建一个好的脚手架

搭建一个好的脚手架,可以更好的编写代码、构建项目等。

能够查看 搭建本身的前端脚手架 了解一些基本的脚手架文件与工具。

好比:

|-- /                              项目根目录
    |-- src/                       源代码目录
    |-- package.json               npm 项目文件
    |-- README.md                  项目说明文件
    |-- CHANGELOG.md               版本更新记录
    |-- .gitignore                 git 忽略配置文件
    |-- .editorconfig              编辑器配置文件
    |-- .npmrc                     npm 配置文件
    |-- .npmignore                 npm 忽略配置文件
    |-- .eslintrc                  eslint 配置文件
    |-- .eslintignore              eslint 忽略配置文件
    |-- .stylelintrc               stylelint 配置文件
    |-- .stylelintignore           stylelint 忽略配置文件
    |-- .prettierrc                prettier 配置文件
    |-- .prettierignore            prettier 忽略配置文件
    
    |-- .babelrc                   babel 配置文件
    |-- webpack.config.js          webpack 配置文件
    |-- rollup.config.js           rollup 配置文件
    |-- gulpfile.js                gulp 配置文件
    
    |-- test/                      测试目录
    |-- docs/                      文档目录
    |-- jest.config.js             jest 配置文件
    |-- .gitattributes             git 属性配置
  • .editorconfig: 用这个文件来统一不一样编辑器的一些配置,好比 tab 转 2 个空格、自动插入空尾行、去掉行尾的空格等,http://editorconfig.org
  • eslintstylelintprettier: 规范化代码风格、优化代码格式等
  • huskylint-staged: 在 git 提交以前对代码进行审查,不然不予提交
  • .gitlab-ci.yml: gitlab ci 持续集成服务

参考:

=================================================

到这里为止,一个基本的项目骨架就算搭建好了。

8. 使用版本控制系统管理源代码(git)

项目搭建好后,须要一个版本控制系统来管理源代码。

比较经常使用的版本管理工具备 gitsvn,如今通常都用 git

通常开源的项目能够托管到 http://github.com,私人的项目能够托管到 https://gitee.comhttps://coding.net/,而企业的项目则须要自建版本控制系统了。

自建版本控制系统主要有 gitlabgogsgiteagitlab 是由商业驱动的,比较稳定,社区版是免费的,通常建议选用这个;gogs, gitea 是开源的项目,还不太稳定,期待进一步的更新。

因此,git + gitlab 是不错的配合。

9. 编写代码

编写代码时,js 选用 es6 的模块化规范来写(若是喜欢用 TypeScript,须要加上 ts-loader),样式能够用 lessscsscss 来写。

js 模块文件时,注释可使用 jsdoc 的规范来写,若是配置相应的工具,能够将这些注释导出接口文档。

由于脚手架里有 huskylint-staged 的配合,因此每次提交的代码都会进行代码审查与格式优化,若是不符合规范,则须要把不规范的代码进行修改,而后才能提交到代码仓库中。

好比 console.log(haha.hehe); 这段代码就会遇到错误,不予提交:

图片描述

这个功能定义在 package.json 中:

{
  "devDependencies": {             工具依赖
    "babel-eslint": "^8.2.6",
    "eslint": "^4.19.1",
    "husky": "^0.14.3",
    "lint-staged": "^7.2.0",
    "prettier": "^1.14.0",
    "stylelint": "^9.3.0",
    "eslint-config-airbnb": "^17.0.0",
    "eslint-config-prettier": "^2.9.0",
    "eslint-plugin-babel": "^5.1.0",
    "eslint-plugin-import": "^2.13.0",
    "eslint-plugin-jsx-a11y": "^6.1.0",
    "eslint-plugin-prettier": "^2.6.2",
    "eslint-plugin-react": "^7.10.0",
    "stylelint-config-prettier": "^3.3.0",
    "stylelint-config-standard": "^18.2.0"
  },
  "scripts": {                     能够添加更多命令
    "precommit": "npm run lint-staged",
    "prettier": "prettier --write \"./**/*.{js,jsx,css,less,sass,scss,md,json}\"",
    "eslint": "eslint .",
    "eslint:fix": "eslint . --fix",
    "stylelint": "stylelint \"./**/*.{css,less,sass,scss}\"",
    "stylelint:fix": "stylelint \"./**/*.{css,less,sass,scss}\" --fix",
    "lint-staged": "lint-staged"
  },
  "lint-staged": {                 对提交的代码进行检查与矫正
    "**/*.{js,jsx}": [
      "eslint --fix",
      "prettier --write",
      "git add"
    ],
    "**/*.{css,less,sass,scss}": [
      "stylelint --fix",
      "prettier --write",
      "git add"
    ],
    "**/*.{md,json}": [
      "prettier --write",
      "git add"
    ]
  }
}
  • 若是你想禁用这个功能,能够把 scripts"precommit" 改为 "//precommit"
  • 若是你想自定 eslint 检查代码的规范,能够修改 .eslintrc, .eslintrc.js 等配置文件
  • 若是你想自定 stylelint 检查代码的规范,能够修改 .stylelintrc, .stylelintrc.js 等配置文件
  • 若是你想忽略某些文件不进行代码检查,能够修改 .eslintignore, .stylelintignore 配置文件

参考:

10. 组件化

当项目拥有了必定量的代码以后,就会发现,有些代码是不少页面共用的,因而把这些代码提取出来,封装成一个组件,供各个地方使用。

当拥有多个项目的时候,有些组件须要跨项目使用,一种方式是复制代码到其余项目中,但这种方式会致使组件代码很难维护,因此,通常是用另外一种方式:组件化。

组件化就是将组件独立成一个项目,而后在其余项目中安装这个组件,才能使用。

通常组件化会配合私有 npm 仓库一块儿用。

|-- project1/ 项目1
    |-- package.json
    
|-- project2/ 项目2
    |-- package.json    

|-- component1/ 组件1
    |-- package.json

|-- component2/ 组件2
    |-- package.json

project1 中安装 component1, component2 组件:

# package.json
{
  "dependencies": {
    "component1": "^0.0.1",
    "component2": "^0.0.1"
  }
}
import compoennt1 from 'compoennt1';
import compoennt2 from 'compoennt2';

若是想要了解怎样写好一个组件(npm package),能够参考 从 1 到完美,写一个 js 库、node 库、前端组件库

参考:

11. 测试

测试的目的在于能以最少的人力和时间发现潜在的各类错误和缺陷,这在项目更新、重构等的过程当中尤为重要,由于每当更改一些代码后,你并不知道这些代码有没有问题、会不会影响其余的模块。若是有了测试,运行一遍测试用例,就知道更改的代码有没有问题、会不会产生影响。

通常前端测试分如下几种:

  1. 单元测试:模块单元、函数单元、组件单元等的单元块的测试
  2. 集成测试:接口依赖(ajax)、I/O 依赖、环境依赖(localStorage、IndexedDB)等的上下文的集成测试
  3. 样式测试:对样式的测试
  4. E2E 测试:端到端测试,也就是在实际生产环境测试整个应用

通常会用到下面的一些工具:

另外,能够参考 聊聊前端开发的测试

12. 构建

通常单页面应用的构建会有 npm run build 的命令来构建项目,而后会输出一个 html 文件,一些 js/css/images ... 文件,而后把这些文件部署到服务器就能够了。

多页面应用的构建要复杂一些,由于是多入口的,因此通常会封装构建工具,而后经过参数传入多个入口:

npm run build -- page1 page2 dir1/* dir2/all --env test/prod
  • page1, page2 肯定构建哪些页面;dir1/*, dir2/all 某个目录下全部的页面;all, * 整个项目全部的页面
  • 有时候可能还会针对不一样的服务器环境(好比测试机、正式机)作出不一样的构建,能够在后面加参数
  • -- 用来分割 npm 自己的参数与脚本参数,参考 npm - run-script 了解详情

多页面应用会导出多个 html 文件,须要注意这些导出的 html 不要相冲突了。

固然,也能够用一些已经封装好的工具,如 lila

13. 部署

在构建好项目以后,就能够部署到服务器了。

传统的方式,能够用 ftp, sftp 等工具,手动传到服务器,但这种方式比较笨拙,不够自动化。

自动化的,能够用一些工具部署到服务器,如 gulpgulp-ssh,固然也能够用一些封装的工具,如 md-synclila

md-sync 为例:

npm install md-sync --save-dev

md-sync.config.js 配置文件:

module.exports = [
  {
    src: './build/**/*',
    remotePath: 'remotePath',
    server: {
      ignoreErrors: true,
      sshConfig: {
        host: 'host',
        username: 'username',
        password: 'password'
      }
    },
  },
  {
    src: './build/**/*.html',
    remotePath: 'remotePath2',
    server: {
      ignoreErrors: true,
      sshConfig: {
        host: 'host',
        username: 'username',
        password: 'password'
      }
    },
  },
];

package.jsonscripts 配置好命令:

"scripts": {
  "deploy": "md-sync"
}
npm run deploy

另外,通常大型项目会使用持续集成 + shell 命令(如 rsync)部署。

14. 持续集成测试、构建、部署

通常大型工程的的构建与测试都会花很长的时间,在本地作这些事情的话就不太实际,这就须要作持续集成测试、构建、部署了。

持续集成工具用的比较多的:

jenkins 是通用型的工具,能够与 githubbitbucketgitlab 等代码托管服务配合使用,优势是功能强大、插件多、社区活跃,但缺点是配置复杂、使用难度较高。

gitlab cigitlab 内部自带的持续集成功能,优势是使用简单、配置简单,但缺点是不及 jenkins 功能强大、绑定 gitlab 才能使用。

gitlab 为例(任务定义在 .gitlab-ci.yml 中):

stages:
  - install
  - test
  - build
  - deploy

# 安装依赖
install:
  stage: install
  only:
    - dev
    - master
  script:
    - npm install

# 运行测试用例
test:
  stage: test
  only:
    - dev
    - master
  script:
    - npm run test

# 编译
build:
  stage: build
  only:
    - dev
    - master
  script:
    - npm run clean
    - npm run build

# 部署服务器
deploy:
  stage: deploy
  only:
    - dev
    - master
  script:
    - npm run deploy

以上配置表示只要在 devmaster 分支有代码推送,就会进行持续集成,依次运行:

  • npm install
  • npm run test
  • npm run clean
  • npm run build
  • npm run deploy

最终完成部署。若是中间某个命令失败了,将中止接下的命令的运行,并将错误报告给你。

这些操做都在远程机器上完成。

=================================================

到这里为止,基本上完成了一个项目的搭建、编写、构建。

15. 清理服务器上过时文件

如今前端的项目基本上都会用 webpack 打包代码,而且文件名(html 文件除外)都是 hash 化的,若是须要清除过时的文件而又不想把服务器上文件所有删掉而后从新构建、部署,可使用 sclean 来清除过时文件。

16. 收集前端错误反馈

当用户在用线上的程序时,怎么知道有没有出 bug;若是出 bug 了,报的是什么错;若是是 js 报错,怎么知道是那一行运行出了错?

因此,在程序运行时捕捉 js 脚本错误,并上报到服务器,是很是有必要的。

这里就要用到 window.onerror 了:

window.onerror = (errorMessage, scriptURI, lineNumber, columnNumber, errorObj) => {
  const data = {
    title: document.getElementsByTagName('title')[0].innerText,
    errorMessage,
    scriptURI,
    lineNumber,
    columnNumber,
    detailMessage: (errorObj && errorObj.message) || '',
    stack: (errorObj && errorObj.stack) || '',
    userAgent: window.navigator.userAgent,
    locationHref: window.location.href,
    cookie: window.document.cookie,
  };

  post('url', data); // 上报到服务器
};

线上的 js 脚本都是压缩过的,须要用 sourcemap 文件与 source-map 查看原始的报错堆栈信息,能够参考 细说 js 压缩、sourcemap、经过 sourcemap 查找原始报错信息 了解详细信息。

参考:

后续

更多博客,查看 https://github.com/senntyou/blogs

做者:深予之 (@senntyou)

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证