fe

2.0.27 • Public • Published

FE

npm version commitizen friendly code style: prettier

Front-End workflow & stack


  • 业务代码回归 最简单 的组织形式:

    index.js
    server
      modules/
        user/
          index.js
    client
      pages/
        index.vue
    
  • 多人协作 / 多 stage 模式下 统一的 环境管理

    # dev stage 
    $ brew install fe
     
    # test stage 
    $ apt-get install fe
     
    # production stage 
    # docker intergration 
    $ npm i fe -g
  • 性能

    • fastify - The fastest and low overhead web framework

    • 最小化业务接口耦合, 根据社区最佳实践持续为生产环境优化, 不再业务中考虑性能优化点

  • less is more

最小约束, 最广泛的项目类似梳理, 支持所有类型项目: SSR / SPA / vue-only / react-only / server-only

  • 同构 模型

基于 next | nuxt 实现 react / vue 同构

  • 完善的 生态
# List resource in fe stack 
$ fe list
# Add deps 
$ fe add

node 环境依赖

  • node 8+

  • npm / yarn(优先)

安装

🎉🎉 推荐 内网急速安装 🎉🎉

$ curl https://code.byted.org/snippets/162/raw -L -o - | sh

标准安装

$ yarn global add fe
# or 
$ npm i fe -g

快速开始

方式一

一般项目开发流程为 1. 通过脚手架创建项目 2. 启动体验良好的开发模式 3. 部署管理

对应命令为:

fe init » fe dev » fe start

方式二

此外也可以建一个空的项目目录原地启动, 当执行 fe dev 时候会检查和通过询问交互的方式最小化配置项目

$ mkdir project && cd project
$ fe dev

代码风格:

严格使用 prettier, 请基于自己的编辑器配置 Editor Support

格式如下

{
  "printWidth": 80,
  "tabWidth": 2,
  "useTabs": false,
  "semi": false,
  "parser": "babylon",
  "singleQuote": true,
  "trailingComma": "none",
  "bracketSpacing": true,
  "jsxBracketSameLine": false,
  "overrides": [
    {
      "files": ".prettierrc",
      "options": { "parser": "json", "trailingComma": "none" }
    },
    {
      "files": ".babelrc",
      "options": { "parser": "json", "trailingComma": "none" }
    },
    {
      "files": "*.json",
      "options": { "trailingComma": "none" }
    }
  ]
}

功能集:

  • dev

    • 前/后端热更新
    • mock
    • proxy
  • start

    • 启动生产环境(需要先 build)
  • add

    • 安装插件并初始化配置?
  • build

    • 构建生产部署代码
  • static

    • 静态化产出物(用以实现 H5 离线化)
  • env

    • 检测并展示环境信息, 便于 DEBUG
    • 实现自检 / 自动修复 / 警告
  • list

    • 展示模板 / 组件 / 中间件 / UI 等生态环境
  • fd

    • 对接公司 consul

前端路由策略

  • "/" => pages/[index.vue | index.js]

  • "/detail" => pages/detail.vue

  • "/sub/detail" => pages/sub/detail.vue

基础业务类型和项目结构:

  • vue-only

    ├── pages
        └── *.vue
    

or

├── client
    └── pages
        └── *.vue
  • react-only

    ├── pages
        └── *.js
    
    ├── client
        └── pages
            └── *.js
    
  • server-only

    └── index.js
    
  • server+vue

    ├── index.js
    └── pages
        └── *.vue
    
  • server+react

    ├── index.js
    └── pages
        └── *.js
    

log 日志

吐槽:fastify 的日志与框架耦合得太深,导致日志的自定义配置比较麻烦

//index.js 入口文件
module.exports = async (app, options) => {
  // ....业务代码
}
// opt参考:https://github.com/fastify/fastify/blob/master/docs/Logging.md
module.exports.logger = opt

bytedance 内部使用

//index.js 入口文件
const { opt, hook } = require('byted-fastify-logger')()
 
module.exports = async (app, options) => {
  hook(app)
  // ....业务代码
}
 
module.exports.logger = opt

业务自定义策略

配置文件

入口文件: /fe.json

对接 fe 框架的配置文件全部放在 CONFIG_DIR

选用 json 格式, 考虑到 fe 某些情况下需要覆写(比如 0 配置启动时, 检测完网络情况后)

默认配置

fe.json 中自定义配置, 优先级策略:

  • babel 配置优先级: .babelrc(如果存在) > BABEL_CONFIG > 默认配置
  • 优先 fe.json , 与下列默认配置浅合并

向后兼容策略, 只增不改

一般地, 值为 "" 的项需要由项目模板中指明, 或者会通过文件检查和询问方式来自动配置

// 当前项目依赖版本, 便于生产环境实施向后版本兼容(遵循 npm version)
// 如果在 package.json 中安装了 `fe` 依赖, 优先级 package.json > fe.json
FE_VERSION: '^2.0.0'
 
// 指定后端服务的入口文件, 如果值为 `null` 意为不需要入口(纯前端项目)
ENTRY_FILE: 'index.js'
 
// [vue | react] 指定前端框架类型, 如果值为 `null` 意为不依赖前端框架
CLIENT_MODE: ''
 
// 前端目录, 纯前端项目: "."; 包含前后端业务, 推荐: "client",
CLIENT_DIR: ''
 
// 无需编译的 public 资源目录(如 favicon)
// 默认访问规则 prefix + PUBLIC_DIR
// 默认文件目录为:
// - project
//   + public
//   + client
//   + server
// 例如:
// http://a.com/web/public/favicon.ico
PUBLIC_DIR: 'public'
 
// URL path prefix
// 访问前缀
// 同时影响: client / server / public 三层访问方式都会增加访问前缀
PREFIX_PATH: ''
 
// 编译后的静态资源访问路径
// 默认为 "/"
// 当需要配置 CDN 时, 这里配置为 CDN 地址
// 例如:
// "PUBLIC_PATH": "//s3a.pstatp.com/caijing/caijing_insurance_quiz/"
PUBLIC_PATH: '/'
 
// 必须的项目配置文件(同时标示项目根目录)
FE_CONFIG_FILE: 'fe.json'
 
// 指定 polyfills 文件名(置于 config 目录中)
// 如需覆盖默认的提供对应文件 (config/polyfills.js), 如需禁用默认的, 提供空文件
POLYFILLS_FILE: 'polyfills.js'
// 指定 setupTests(单测环境配置) 文件名
SETUP_TESTS_FILE: 'setupTests.js'
 
// 前端构建目录
DIST_DIR: 'build'
// 项目级别扩展配置文件目录(非业务相关)
CONFIG_DIR: 'config'
 
// 开发模式下会启动一个 mock 服务, 通过 `/_mock` 访问
MOCK_PREFIX: '/_mock'
// mock 存放目录
MOCK_DIR: 'mock'
 
// 是否启动服务端渲染
ENABLE_SSR: true
 
// 是否启用 PWA
ENABLE_PWA: false
 
// 默认在开发环境添加 Access-Control-Allow-Origin CORS header
// 生成环境请在 .env 中配置
CORS_ORIGIN: '*'
CORS_METHODS: 'GET,HEAD,PUT,PATCH,POST,DELETE'
 
// 是否启用 https
ENABLE_HTTPS: false
 
// 开发服务器 ip
DEV_SERVER_IP: '0.0.0.0'
// 开发服务器占用端口(生产环境配置以 `.env` 方式提供)
DEV_SERVER_PORT: 3000
 
// 判定是否在国内, 影响从哪安装 npm 包等策略, 项目初始化时检测一次, 后续手动执行 `fe env` 再次检查并更新
IN_CHINA: true

其他内置插件配置文件:

config/plugins/
  webpack.config.js
  babel.config.js
  # 开发模式下会启动一个 proxy 服务 
  proxy.config.js
  postcss.config.js
  ...

环境变量

每次上线前保证 .env , 用以生产环境

# 项目唯一标示
PSM=caijing.xx.xx

TCE 上线策略

生产环境 server 启动时会检查环境变量: IS_HOST_NETWORK , 命中 "HOST" 模式后, 会优先绑定 PORT0 (由 TCE 注入环境变量), 否则会命中 "bridge" 模式, 读取 .env 文件中的 SERVER_PORT 作为绑定端口, 简单来说: HOST / AUTOHOST 模式下绑定端口由 TCE 自动分配, BRIDGE 模式下绑定端口从 .env > SERVER_PORT 中读取

热更新策略

  • 前端 Hot Module Reloading (尽量不刷新页面)
  • 后端的更新避免触发前端重新编译
  • 支持 fe.json
  • 支持 package.json 安装新模块后热更新

fe dev 启动策略:

  1. 检查是否存在 fe.json
  • NO
      1. 询问是否在当前目录自动创建 fe.json 或 "You'd better use fe init [template name] initialize a new project"
  • YES - GOTO 2.
  1. 检查 CLIENT_MODE

    • null - 按纯服务端启动

    • 如果为 ""

      • 检查 CLIENT_DIR, 如果为 "":

        • 如果存在目录 /pages / /client/pages 更新 CLIENT_DIR,
        • 如果存在 CLIENT_DIR 对应目录, 检查 /pages/*.vue / /client/pages/*.vue 自动判断前端框架, 更新 CLIENT_MODE
      • 否则询问 "Do you need vue / react as front-env framework and auto create pages folder?"

      • 询问 "Includes server business in your project?"

        • NO => 创建 pages/index.vue 并更新 CLIENT_MODECLIENT_DIR
        • YES => 创建 client/pages/index.vueserver/.gitkeep, 并更新 CLIENT_MODECLIENT_DIR
  2. 检查 ENTRY_FILE 文件是否存在

  • 如果不存在询问 "Not found index.js as entry file, auto generate a new file?", 如果选 NO, 配置 ENTRY_FILEnull, 否则创建:
module.exports = async (app, options) => {
  app.get('/', (req, res) => {
    hello: 'world'
  })
  // app.register(require('./server/modules/user/'), { prefix: '/api/user' })
}

fe start 启动策略

  • 检查是否存在 fe.json 抛出错误 "Not specified fe.json"
  • 检查是否存在 build 产出物

fe init 策略

download => replace => check in china => yarn / npm install


start | dev 区别

dev 模式用于本地开发, 忽略 .env 环境变量, 相关配置汇总在 fe.json;

包含 mock / 文档等开发服务

start 模式就是线上运行环境, 优先以 .env 方式配置环境变量;

最小化启动, 性能优先

环境判断:

  1. 按不同执行命令 => 显示注入到 process.env.NODE_ENV = production|development
  2. 业务中判断环境模式: const dev = process.env.NODE_ENV !== 'production'

目前 require 方式导致 fe 主命令启动太慢

=> actions 按文件分拆出去


css 方案梳理

主要基于 postcss

设计图

尺寸约定为 750 x 1334

配置优先级

project/config/postcss.config.js > fe default

方案选型

  • 资源引入

    • postcss-import (default)
    • postcss-url (default)
  • 屏幕适配

    • postcss-px-to-viewport
    • postcss-viewport-units
    • viewport-units-buggyfill
  • 新特性

    • postcss-cssnext (default 已包含 autoprefixer)
  • 压缩 / 清理无用

    • cssnano
  • 1px

    • postcss-write-svg

默认配置:

const createResolver = require('postcss-import-resolver')
module.exports = runtime => ({
  plugins: [
    require('postcss-import')({
      resolve: createResolver({
        alias: {
          '~': runtime.project.CLIENT_DIR,
          '~~': runtime.project.appRoot,
          '@': runtime.project.CLIENT_DIR,
          '@@': runtime.project.appRoot
        },
        modules: [
          runtime.project.CLIENT_DIR,
          runtime.project.appRoot,
          'node_modules',
          runtime.ENV.internalModulePath
        ]
      })
    }),
    require('postcss-url')(),
    require('postcss-cssnext')()
  ]
})

自定义配置: config/postcss.config.js

module.exports = (config, runtime) => {
  config.plugins.push(
    require('autoprefixer')({
      /* ...options */
    })
  )
  return config
}

H5 的自定义配置梳理: config/postcss.config.js

module.exports = (config, runtime) => {
  config.plugins.concat([
    require('postcss-write-svg')({
      utf8: false
    }),
    require('postcss-px-to-viewport')({
      viewportWidth: 750,
      viewportHeight: 1334,
      unitPrecision: 3,
      viewportUnit: 'vw',
      selectorBlackList: ['.nvw', '.hairlines'],
      minPixelValue: 1,
      mediaQuery: false
    }),
    require('postcss-viewport-units')()
  ])
  return config
}

使用指南

  1. 资源引入

client 目录 => ~ | @ root 目录 => ~~ | @@

@import 'cssrecipes-defaults'/* == @import "../node_modules/cssrecipes-defaults/index.css"; */
@import 'normalize.css'/* == @import "../node_modules/normalize.css/normalize.css"; */
 
@import 'foo.css'/* relative to css/ according to `from` option above */
 
@import 'bar.css' (min-width: 25em);
 
.element {
  background: url('images/sprite.png');
}
<img src="~assets/lark.png" alt="">
<img src="/public/lark.png" alt="">

https://github.com/postcss/postcss-url > https://github.com/postcss/postcss-url

https://github.com/postcss/postcss-import

  1. 使用 cssnext
/* custom properties */
:root {
  --fontSize: 1rem;
  --mainColor: #12345678;
  --highlightColor: hwb(19035%20%);
}
 
/* custom properties set & @apply rule */
:root {
  --centered: {
    display: flex;
    align-items: center;
    justify-content: center;
  }
}
 
.centered {
  @apply --centered;
}
 
/* custom media queries */
@custom-media --viewport-medium (width <= 50rem);
 
/* some var() & calc() */
body {
  color: var(--mainColor);
 
  font-size: var(--fontSize);
  line-height: calc(var(--fontSize) * 1.5);
  padding: calc((var(--fontSize) / 2) + 1px);
}
 
/* custom media query usage */
@media (--viewport-medium) {
  body {
    font-size: calc(var(--fontSize) * 1.2);
  }
}
 
/* custom selectors */
@custom-selector :--heading h1h2h3h4h5h6;
:--heading {
  margin-top: 0;
}
 
/* image-set function */
.foo {
  background-image: image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
}
 
/* colors stuff */
a {
  color: var(--highlightColor);
  transition: color 1s; /* autoprefixed ! */
}
a:hover {
  color: gray(25550%);
}
a:active {
  color: rebeccapurple;
}
a:focus {
  background-color: rgb(255 153 0 / 33%);
  outline: 3px solid hsl(1turn 60% 50%);
}
a:any-link {
  color: color(var(--highlightColor) blackness(+20%));
}
 
/* font stuff */
h2 {
  font-variant-caps: small-caps;
}
 
table {
  font-variant-numeric: lining-nums;
}
 
/* filters */
.blur {
  filter: blur(4px);
}
.sepia {
  filter: sepia(0.8);
}
 
/* overflow-wrap fallback */
body {
  overflow-wrap: break-word;
}
 
/* attribute case insensitive */
[frame='hsides' i{
  border-style: solid none;
}
 
/* system-ui font-family */
body {
  font-family: system-ui;
}

http://cssnext.io/postcss/

  1. 1px 适配
/*border-image*/
@svg 1px-border {
  height: 2px;
 
  @rect {
    fill: var(--color, black);
    width: 100%;
    height: 50%;
  }
}
 
.example {
  border: 10px solid transparent;
  border-image: svg(1px-border param(--color #00b1ff)) 2 2 stretch;
}
 
/*background-image*/
@svg square {
  @rect {
    fill: var(--color, black);
    width: 100%;
    height: 100%;
  }
}
 
#example {
  background: white svg(square param(--color #00b1ff));
}

https://github.com/jonathantneal/postcss-write-svg

  1. 屏幕适配

基于 vw 方案, android 4.4 下 polyfill 处理:

require('viewport-units-buggyfill').init();

启用 polyfill 后, 可大胆使用 vw vh vmin vmax 单位, 在基于设计稿开发时, 请确保设计图为 750 x 1334(否则自定义 config/postcss.config.js), 在 css 中直接按设计图尺寸书写 px 单位, 预编译阶段会将 px 单位转换为 vw, 如果需要忽略转换, 请添加 .nvw class

https://github.com/rodneyrehm/viewport-units-buggyfill


项目开发贡献指南

开发

  1. fork => MR => review => merge

  2. 开发时建议测试驱动, 在 test 目录先写 case, 再写业务代码

$ npm run dev

TIPS 增加 DEBUG=inspect 环境变量(DEBUG=inspect fe dev) 执行可以用 chrome devtools 来 debug node

  1. 注意 git commit 的代码格式
# git commit 格式化 
$ npm run commit
  1. 注意代码风格

发版流程

  1. Commit changes

    $ git add .
    $ npm run commit
  2. Bump version via npm

    $ npm version patch
  3. Generate CHANGELOG.md

    $ npm run changelog
  4. Commit CHANGELOG

    $ npm run commit
  5. Release new version

    $ npm run release
    # scp ... 

then, github release.. etc.


DEBUG 方法:

  1. pgrep -n node | xargs kill -USR1
  2. node -e "process._debugProcess(pid)"
  3. INSPECT=--inspect fe d

Readme

Keywords

none

Package Sidebar

Install

npm i fe

Weekly Downloads

32

Version

2.0.27

License

ISC

Unpacked Size

97.7 kB

Total Files

66

Last publish

Collaborators

  • leecade
  • wangcong