npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fe

v2.0.27

Published

Front-End workflow & stack

Downloads

142

Readme

FE

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(190, 35%, 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 h1, h2, h3, h4, h5, h6;
:--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(255, 50%);
}
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