前端-工程目录规范

1,724 阅读9分钟

背景

为了统一团队的研发方式,对团队代码资产的目录结构做最佳实践的统一规范,降低对于各类代码资产的理解、维护成本,并方便统一的构建和管理。

规范细则

以下关键词 MUST、MUST NOT、REQUIRED、SHALL、SHALL NOT、SHOULD、SHOULD NOT、 RECOMMENDED、MAY、OPTIONAL 依照 RFC 2119 的叙述解读。

目录划分原则

  • 根目录下必须(MUST)按照职能进行划分,禁止(MUST NOT)按照业务功能进行目录划分,帮助开发同学快速聚焦关注点

    • 根目录下文件夹必须(MUST)只能包含src/、bin/、config/、tests/、public/、build/ 这六个。

      • src文件夹下存放业务源码
      • config文件夹下存放配置相关文件
      • public文件夹下存放通用html模版
      • bin文件夹下存放执行脚本文件
      • build文件夹下存放打包后代码
      • tests文件夹下存放测试相关代码
    • 根目录下还应该(SHOULD)包含package.json、README.md、yarn.lock、.commitlintrc.js、.cz-configrc.js、.editorconfig、.eslintrc.js、.stylelintrc、babel.config.js、.eslintignore、.gitignore、.stylelintignore、.npmrc、vue.config.js、tsconfig.json、.env.*等配置文件。其中必须(MUST)包含package.json、README.md、yarn.lock、.commitlintrc.js、.cz-configrc.js、.editorconfig、.eslintrc.js、.stylelintrc、babel.config.js来完成依赖管理、工程说明、依赖版本锁定以及代码书写规范约束。

  • 对于业务不需要分包进行独立管理依赖的情况在src下面直接按照职能类型进行划分

    • src下必须(MUST)是components/、lib/、api/、plugins/、assets/、styles/、pages/中的若干个。随着资源职能的增加可能会增加对应的目录,例如目前探索的hooks纯逻辑复用方式,可申请新增。

      • 公共组件应该(SHOULD)放在components/下面

        • 组件必须(MUST)创建组件文件夹进行放置

          • 组件可以(MAY)在多层目录下放置,如 components/module-a/module-b/.../componentxx

            • [规范补充]:

              • 根节点组件定义:导出一个index.vue文件的文件夹则被视为根节点组件,即该文件夹下应该只包含书写这个组件所需要的资产。

              • 根节点组件目录结构

                • 必须导出index.vue文件作为组件的解析入口

                • 子目录可以(CAN)包含 components/styles/assets/api这几个文件夹,除此之外不可以包含其他文件夹

                  • components:存放该业务组件的子组件
                  • styles:存放该业务组件抽取的样式文件,不过更推荐内联到.vue文件中
                  • assets:存量只属于该组件静态文件如图片
                  • api:存放只属于该组件的api文件
                • 其中components下和src下components目录规范要求相同,不过原则上应该只包含它父组件的子组件

        • 组件必须(MUST)实现index.vue文件来导出组件

        • 组件的注释规范见[资产注释规范]

      • 公共工具函数应该(SHOULD)放在lib/下面

      • 公共后台接口服务应该(SHOULD)放在api/**下面

        • 如果要放置页面api文件,推荐( RECOMMENDED)和页面文件夹名称对应。
      • 公共插件、过滤器(Vue.filter)、自定义指令(Vue.directive)应该(SHOULD)放在plugins/**下面

        • 公共插件推荐( RECOMMENDED)实现Vue.use(plugin),页面只需引入即可使用
      • 公共静态资源如图片应该(SHOULD)放在assets/**下面

        • assets下如需按照静态资源类型存放可按照imgs、fronts、js、css进行划分。
      • 公共动态样式文件应该(SHOULD)放在styles/**下面

      • 页面必须(MUST)放在pages/下面

        • 页面代码必须(MUST)创建页面文件夹进行放置,如pages/businessxx/

        • 页面文件夹中必须(MUST)实现main.js和app.vue文件

        • 页面文件夹中允许(SHOULD)包含页面级别的 components/、lib/、api/、assets/、styles/、router/、store/、views/文件夹

        • 如果该页面为单页应用入口,其中单页的页面文件必须放在views/文件夹下面,如 views/businessxx.vue

          • views下的一个单页应用的页面必须(MUST)实现.vue的单文件,或按如下规则内聚:

            • views/xx 可以作为一个单独的模块,允许(MAY)有模块自己的 api、lib、styles、components 子目录
            • 子目录都同样支持多级嵌套
            • api 和 lib:允许 .js、.ts 文件,分别放请求代码和工具/配置代码
            • styles:允许 .scss、.css 样式文件
            • components:内部和公共组件目录规范细则一致
            • 如果只有一个文件不希望建一个单独的子目录,也可以直接在模块中创建 api.{js|ts}、lib.{js|ts}、styles.{scss|css} 这几个单文件
          • views下的一个单页应用页面可以(MAY)在多层目录下放置,如 views/module-a/module-b/.../businessxx.vue

        • 单页应用的路由配置放在router/文件夹下,入口为index.js

        • 单页应用的全局数据相关放在store/文件夹下,入口为index.js

        • 如果页面要自定义html模版,则还可以(MAY)包含businessxx.html文件,其中businessxx和页面文件夹同名。

  • TS 工程的目录结构和 ES 工程基本一致。允许在 src 目录放置 types、Must 级别的 .js 文件可以修改为 .ts 文件

  • 对于业务需要使用多包方式独立管理依赖的情况,src下增加packages,packages下按照业务功能划分目录,如src/packages/**/,业务功能文件夹下按照职能进行划分。原则同上。

目录命名原则

  • 命名尽量简洁,有习惯缩写的单词用缩写的形式
  • 目录和文件名称统一使用小写加连字符((kebab-case))

目录结构说明

一个复杂应用的目录结构如下,涵盖了中后台开发的各种功能和坑位。

代码块

system-demo
├─ src 
│    ├─ components //页面间复用组件。根据组件模版生成的组件放在这个文件夹中。页面间复用的组件可以快速被沉淀为平台组件(发布为npm包,各个其他项目中以npm包的方式进行引用)
│    │    ├─ strong-hello-world
│    │    │    └─ index.vue //组件入口文件
│    │    ├─ module-a // 多级目录
│    │    │    ├─ module-b
│    │    │    │    ├─ home-page //组件根节点
│    │    │    │    │    ├─ components //[可选] 子组件目录,内部的目录结构和外层 components 目录一致
│    │    │    │    │    ├─ styles //[可选] 组件样式文件
│    │    │    │    │    │    └─ index.scss
│    │    │    │    │    ├─ assets //[可选] 组件静态资源
│    │    │    │    │    │    └─ home-page.png
│    │    │    │    │    ├─ api //[可选] 组件接口服务
│    │    │    │    │    │    └─ index.js
│    │    │    │    │    └─ index.vue //组件入口文件
│    ├─ lib //工具库
│    │    ├─ http.js
│    │    └─ axios.js
│    ├─ api //后台接口服务
│    │    └─ common.js //公共接口
│    ├─ plugins //[可选] vue插件(全局)
│    │    └─ mtd.js 
│    ├─ assets //[可选] 静态资源
│    │    └─ pic.png 
│    ├─ styles //[可选] 样式资源
│    │    └─ global.scss
│    ├─ pages //页面,pages下的每个文件夹都会被作为一个entry来进行打包(必须,打包时路由解析会依赖这个文件目录)
│    │    ├─ page-a // 每一个页面内部可以实现为一个spa
│    │    │    ├─ main.js //页面打包主入口
│    │    │    ├─ app.vue  //页面入口vue文件,作为页面组件进行解析
│    │    │    ├─ router //spa路由配置
│    │    │    │    └─ index.js
│    │    │    ├─ store //[可选] 页面store
│    │    │    │    └─ index.js //store入口文件
│    │    │    ├─ views //视图文件,仅允许 .vue 文件
│    │    │    │    ├─ module-a //可多级嵌套
│    │    │    │    │    └─ module-a-page.vue
│    │    │    │    ├─ home-page.vue
│    │    │    │    └─ about-page.vue
│    │    │    ├─ lib //[可选] 页面级工具库
│    │    │    │    └─ page-a-utils.js
│    │    │    ├─ assets //[可选] 页面级静态资源
│    │    │    │    └─ about.png
│    │    │    ├─ styles //[可选] 页面级样式资源
│    │    │    │    ├─ home.scss
│    │    │    │    └─ about.scss
│    │    │    ├─ api //[可选] 页面级后台接口服务
│    │    │    │    └─ page-a.js //page-a接口
│    │    │    ├─ components // [可选] 页面级组件,比如使用到store的组件都可以放在此目录下
│    │    │    │    └─ pagea-hello-world
│    │    │    │    │    └─ index.vue
│    │    │    ├─ page-a.html  //[可选] 页面打包模版,如果不想用默认打包模版可以自定义
│    │    ├─ page-b
│    │    │    ├─ main.js //打包主入口
│    │    │    ├─ app.vue  //页面入口vue文件
│    │    │    ├─ store //[可选] 页面store
│    │    │    │    └─ index.js //store入口文件
│    │    │    ├─ api //[可选] 页面级后台接口服务
│    │    │    │    └─ page-b.js //page-b接口
│    │    │    ├─ components // [可选] 页面级组件,比如使用到store的组件都可以放在此目录下
│    │    │    │    └─ pagea-hello-world
│    │    │    │    │    └─ index.vue
│    │    │    ├─ page-b.html  //[可选] 页面打包模版,如果不想用默认打包模版可以自定义
│    ├─ types //[可选] TS 工程类型声明文件
├─ public 必须 //默认项目打包html模版
│    └─ index.html
├─ README.md 必须
├─ package.json 必须
//标准化工程规范
├─ .commitlintrc.js 必须
├─ .cz-configrc.js 必须
├─ .editorconfig 必须
├─ .eslintignore 必须
├─ .eslintrc.js 必须
├─ .gitignore 必须
├─ .stylelintrc.js 必须
//工程配置文件
├─ .env.development 必须 //不同环境的变量配置 
├─ .env.production 必须 
├─ .env.staging 必须
├─ tsconfig.json [可选]
├─ vue.config.js //打包主配置文件
//工程配置文件
├─ config 
│    └─ variables.config.js //其他打包所需配置文件,编译时插件可定制的配置文件
//执行文件
├─ bin
//打包文件夹build
├─ build 
//单元测试文件
└─  tests 
     └─ unit
            ├─ .eslintrc.js
            └─ example.spec.js

由于有业务团队有多包方式独立管理不同业务模块之间依赖的需求,因此同时研发框架的目录结构同时支持了多包目录结构,如下所示。

代码块

system-demo
├─ src 
│    ├─ packages
│    │    ├─ bushiness1
│    │    │    ├─ ... //同上述目录结构中src中的内容
│    │    │    └─ package.json // package1独立业务依赖,如业务组件库等
├─ public 必须 //默认项目打包html模版
│    ├─ favicon.ico
│    └─ index.html
├─ README.md 必须
├─ package.json 必须
//标准化工程规范
├─ .commitlintrc.js 必须
├─ .cz-configrc.js 必须
├─ .editorconfig 必须
├─ .eslintignore 必须
├─ .eslintrc.js 必须
├─ .gitignore 必须
├─ .stylelintrc.js 必须
//工程配置文件
├─ .env.development 必须 //不同环境的变量配置 
├─ .env.production 必须 
├─ .env.staging 必须
├─ vue.config.js //打包主配置文件
//工程配置文件
├─ config 
│    └─ variables.config.js //其他打包所需配置文件,编译时插件可定制的配置文件
//执行文件
├─ bin
//打包文件夹build
├─ build 
//单元测试文件
└─  tests 
     └─ unit
            ├─ .eslintrc.js
            └─ example.spec.js

工程内部资产生产规范

其中为了进行资产的结构化解析以及自动化构建能力,研发框架又规定了组件和页面的生产规范。

组件生产规范

其中页面间复用的组件(src下包含的components)和页面级组件(每个page文件夹下包含的components)都需要约定如下目录结构书写([组件目录结构规范])。必须实现index.vue文件作为组件的入口文件。方便研发框架对组件进行结构化的解析以及对接平台化的资产注册。注释规范遵循[资产注释规范]

代码块

├─ components //页面间复用组件。根据组件模版生成的组件放在这个文件夹中。页面间复用的组件可以快速被沉淀为平台组件(发布为npm包,各个其他项目中以npm包的方式进行引用)
│    └─ strong-hello-world
│           └─ index.vue //组件入口文件
│    └─ second-demo
│           └─ index.vue
│           └─ second.vue

页面生产规范

对于每个页面(pages下的每个文件夹),都需要实现main.js打包入口文件,以及app.vue的入口文件。方便统一构建做自动化的打包入口计算。

代码块

├─ pages //页面间复用组件。根据组件模版生成的组件放在这个文件夹中。页面间复用的组件可以快速被沉淀为平台组件(发布为npm包,各个其他项目中以npm包的方式进行引用)
│    └─ page-demo
│    │    ├─ main.js //页面打包主入口
│    │    ├─ app.vue  //页面入口vue文件

参考文献