- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
作者:京东零售 吴迪 。
在实际项目开发中无论 M 端、PC 端,或多或少都有一个 utils 文件目录去管理项目中用到的一些常用的工具方法,比如:时间处理、价格处理、解析url参数、加载脚本等,其中很多是重复、基础、或基于某种业务场景的工具,存在项目间冗余的痛点以及工具方法规范不统一的问题.
构建工具库底层架构大概需要哪些功能的支持:
在对底层架构设计的基础上,首先需要把用到的依赖库简单熟悉一下:
• rollup(工具库打包构建核心包) 。
• rollup-plugin-livereload(rollup 插件,热更新,方便本地 debugger 开发) 。
• rollup-plugin-serve(rollup 插件,本地服务代理,方便在本地 html 中调试工具) 。
• rollup-plugin-terser(rollup 插件,代码压缩混淆) 。
• rollup-plugin-visualizer(rollup 插件,可视化并分析 Rollup bundle,以查看模块占用) 。
• @rollup/plugin-babel(rollup 插件,rollup 的 babel 插件,ES6 转 ES5) 。
• @rollup/plugin-commonjs(rollup 插件,用来将 CommonJS 模块转换为 ES6,这样它们就可以包含在 Rollup 包中) 。
• @rollup/plugin-json(rollup 插件,它将.json 文件转换为 ES6 模块) 。
• @rollup/plugin-node-resolve(rollup 插件,它使用节点解析算法定位模块,用于在节点模块中使用第三方 node_modules 包) 。
• @rollup/plugin-typescript(rollup 插件,对 typescript 的支持,将 typescript 进行 tsc 转为 js) 。
• typescript(使用 ts 开发工具库) 。
• tslib(TypeScript 的运行库,它包含了 TypeScript 所有的帮助函数) 。
• @typescript-eslint/eslint-plugin(TypeScript 的 eslint 插件,约束 ts 书写规范) 。
• @typescript-eslint/parser(ESLint 解析器,它利用 TypeScript ESTree 来允许 ESLint 检测 TypeScript 源代码) 。
• typedoc(TypeScript 项目的文档生成器) 。
• gulp(使用 gulp 构建文档系统) 。
• gulp-typedoc(Gulp 插件来执行 TypeDoc 工具) 。
• browser-sync(文档系统热更新) 。
• jest(一款优雅、简洁的 JavaScript 测试框架) 。
• @types/jest(Jest 的类型定义) 。
• ts-jest(一个支持源映射的 Jest 转换器,允许您使用 Jest 来测试用 TypeScript 编写的项目) 。
• @babel/preset-typescript(TypeScript 的 Babel 预设) 。
• eslint(代码规范约束) 。
• @babel/core(@rollup/plugin-babel 依赖的 babel 解析插件) 。
• @babel/plugin-transform-runtime(babel 转译依赖) 。
• @babel/preset-env(babel 转译依赖) 。
• chalk(控制台字符样式) 。
• rimraf(UNIX 命令 rm -rf 用于 node) 。
• cross-env(跨平台设置 node 环境变量) 。
新建一个文件夹 utils-demo,执行 npm init,过程会询问构建项目的基本信息,按需填写即可:
npm init
创建工具库业务开发 src 文件目录,明确怎样规划工具库包,里面放置的是工具库开发需要的业务代码:
要对 typescript 代码进行解析支持需要安装对 ts 支持的依赖,以及对开发的工具的一些依赖包:
yarn add typescript tslib rollup rollup-plugin-livereload rollup-plugin-serve rollup-plugin-terser rollup-plugin-visualizer
@rollup/plugin-babel @rollup/plugin-commonjs @rollup/plugin-json @rollup/plugin-node-resolve @rollup/plugin-typescript
@babel/core @babel/plugin-transform-runtime @babel/preset-env rimraf lodash chalk@^4.1.2 -D
这里遇到一个坑,关于最新 chalk5.0.0 不支持在 nodejs 中 require()导入,所以锁定包版本 chalk@^4.1.2 。
要对 typescript 进行解析和编译还需要配置 tsconfig.json,该文件中指定了用来编译这个项目的根文件和编译选项,在项目根目录,使用 tsc --init 命令快速生成 tsconfig.json 文件(前提全局安装 typescript) 。
npm i typescript -g
tsc --init
初始化 tsconfig 完成之后,根目录自动生成 tsconfig.json 文件,需要对其进行简单的配置,以适用于 ts 项目,其中具体含义可以参考 tsconfig.json 官网 。
生成rollup配置项函数核心代码:
const moduleName = camelCase(name) // 当format为iife和umd时必须提供,将作为全局变量挂在window下:window.moduleName=...
const banner = generateBanner() // 包说明文案
// 生成rollup配置文件函数
const generateConfigs = (options) => {
const { input, outputFile } = options
console.log(chalk.greenBright(`获取打包入口:${input}`))
const result = []
const pushPlugins = ({ format, plugins, ext }) => {
result.push({
input, // 打包入口文件
external: [], // 如果打包出来的文件有项目依赖,可以在这里配置是否将项目依赖一起打到包里面还是作为外部依赖
// 打包出口文件
output: {
file: `${outputFile}${ext}`, // 出口文件名称
sourcemap: true, // // 是否生成sourcemap
format, // 打包的模块化格式
name: moduleName, // 当format为iife和umd时必须提供,将作为全局变量挂在window下:window.moduleName=...
exports: 'named' /** Disable warning for default imports */,
banner, // 打包出来的文件在最顶部的说明文案
globals: {} // 如果external设置了打包忽略的项目依赖,在此配置,项目依赖的全局变量
},
plugins // rollup插件
})
}
buildType.forEach(({ format, ext }) => {
let plugins = [...defaultPlugins]
// 生产环境加入包分析以及代码压缩
plugins = [
...plugins,
visualizer({
gzipSize: true,
brotliSize: true
}),
terser()
]
pushPlugins({ format, plugins, ext })
})
return result
}
{
"presets": [
[
"@babel/preset-env"
]
],
"plugins": ["@babel/plugin-transform-runtime"]
}
"scripts": {
"build": "rimraf lib && rollup -c ./scripts/rollup.config.js" // rollup打包
},
项目搭建到这里,不知机智的你能否发现问题:
• 我想使用该包里面 date 相关工具,要这样吗?
import { dateA, dateB, dateC } from "utils-demo"
能不能这样?
import { date } from "utils-demo"
date.dateA()
date.dateB()
date.dateC()
• 在一些使用 script 脚本引入的场景下,就仅仅需要 date 相关的工具,要这样吗?
<script src="https://xxx/main.min.js">
能不能这样?
<script src="https://xxx/date.min.js">
这样仅仅使用 date 里面的工具,就没有必要将所有的工具都引入了 。
解决方案:
自动构建入口文件核心代码:
const fs = require('fs') // node fs模块
const chalk = require('chalk') // 自定义输出样式
const { resolveFile, getEntries } = require('./utils')
let srcIndexContent = `
// tips:此文件是自动生成的,无需手动添加
`
getEntries(resolveFile('src/modules/*')).forEach(({ baseName, entry }) => {
let moduleIndexContent = `
// tips:此文件是自动生成的,无需手动添加
`
try {
// 判断是否文件夹
const stats = fs.statSync(entry)
if (stats.isDirectory()) {
getEntries(`${entry}/*.ts`).forEach(({ baseName }) => {
baseName = baseName.split('.')[0]
if (baseName.indexOf('index') === -1) {
moduleIndexContent += `
export * from './${baseName}'
`
}
})
fs.writeFileSync(`${entry}/index.ts`, moduleIndexContent, 'utf-8')
srcIndexContent += `
export * from './modules/${baseName}'
export * as ${baseName} from './modules/${baseName}'
`
} else {
srcIndexContent += `
export * from './modules/${baseName.split('.')[0]}'
`
}
} catch (e) {
console.error(e)
}
})
fs.writeFileSync(resolveFile('src/index.ts'), srcIndexContent, 'utf-8')
至此,基本上解决了工具库打包的问题,但是架构中还缺少本地开发调试的环境,下面为大家介绍如何架构中添加本地开发调试的系统.
首先要明确要加入本地开发调试系统的支持,需要做到以下:
• 跨平台(window不支持NODE_ENV=xxx)设置环境变量,根据环境配置不同的 rollup 配置项 。
• 引入本地开发需要的 html 静态服务器环境,并能做到热更新 。
yarn add cross-env -D
"scripts": {
"entry": "node ./scripts/build-entry.js",
"dev": "rimraf lib && yarn entry && cross-env NODE_ENV=development rollup -w -c ./scripts/rollup.config.js", // -w 表示监听的工具模块的修改
"build": "rimraf lib && yarn entry && cross-env NODE_ENV=production rollup -c ./scripts/rollup.config.js"
},
(isProd ? buildType : devType).forEach(({ format, ext }) => {
let plugins = [...defaultPlugins]
if (isProd) {
// 生产环境加入包分析以及代码压缩
plugins = [...plugins, visualizer({
gzipSize: true,
brotliSize: true
}), terser()]
} else {
// 非生产环境加入热更新和本地服务插件,方便本地debugger
plugins = [...plugins, ...[
// 热更新
rollUpLiveLoad({
watch: ['debugger', 'lib'],
delay: 300
}),
// 本地服务代理
rollupServe({
open: true,
// resolveFile('')代理根目录原因是为了在ts代码里debugger时可以方便看到调试信息
contentBase: [resolveFile('debugger'), resolveFile('lib'), resolveFile('')]
})
]]
}
pushPlugins({ format, plugins, ext })
})
一个完备的工具库需要有一个文档来展示开发的工具函数,它可能需要具备以下几点支持:
• 支持工具库中方法的可视化预览 。
• 支持修改工具的时候,具备热更新机制 。
typedoc (TypeScript 项目的文档生成器)能完美支持 typescript 开发工具库的文档生成器的支持,它的核心原理就是读取源代码,根据工具的注释、ts的类型规范等,自动生成文档页面 。
关于热更新机制的支持,第一个自然想到 browser-sync (文档系统热更新) 。
由于文档系统的预览功能有很多插件组合来实现的,可以借助 gulp (基于流的自动化构建工具),typedoc正好有对应的 gulp-typedocGulp 插件来执行 TypeDoc 工具插件 。
构建完成后打开文档系统,并且它是热更新的,修改工具方法后自动更新文档:
为确保用户使用的工具代码的安全性、正确性以及可靠性,工具库的单元测试必不可少。单元测试选用的是 Facebook 出品的 Jest 测试框架,它对于 TypeScript 有很好的支持.
npm jest -g
jest --init
下面是本人设置的jest的配置项
✔ Would you like to use Jest when running "test" script in "package.json"? … yes
✔ Would you like to use Typescript for the configuration file? … yes
✔ Choose the test environment that will be used for testing › jsdom (browser-like)
✔ Do you want Jest to add coverage reports? … yes
✔ Which provider should be used to instrument code for coverage? › babel
✔ Automatically clear mock calls, instances and results before every test? … yes
执行完之后根目录会自动生成jest.config.ts 文件,里面设置了单元测试的配置规则,package.json 里面也多了一个 script 指令 test.
yarn add jest ts-jest @babel/preset-typescript @types/jest -D
{
"presets": [
"@babel/preset-typescript",
[
"@babel/preset-env"
]
],
"plugins": ["@babel/plugin-transform-runtime"]
}
可以看到关于 debounce 防抖工具函数的测试情况显示在了控制台:
• stmts 是语句覆盖率(statement coverage):是不是每个语句都执行了?
• Branch 分支覆盖率(branch coverage):是不是每个 if 代码块都执行了?
• Funcs 函数覆盖率(function coverage):是不是每个函数都调用了?
• Lines 行覆盖率(line coverage):是不是每一行都执行了?
每次修改单元测试都要执行 yarn test 去查看测试结果,怎么解决?
jest提供了 watch 指令,只需要配置 scripts 脚本就可以做到,单元测试的热更新.
"scripts": {
"test": "jest --watchAll"
},
以后会写很多工具的测试用例,每次 test 都将所有工具都进行了测试,能否只测试自己写的工具?
jest 也提供了测试单个文件的方法,这样 jest 只会对防抖函数进行测试(前提全局安装了 jest).
jest debounce.test.ts --watch
至此工具库距离开发者使用仅一步之遥,就是发布到npm上,发包前需要在 package.json 中声明库的一些入口,关键词等信息.
"main": "lib/main.js", // 告知引用该包模块化方式的默认文件路径
"module": "lib/main.esm.js", // 告知引用该包模块化方式的文件路径
"types": "lib/types/index.d.ts", // 告知引用该包的类型声明文件路径
"sideEffects": false, // false 为了告诉 webpack 我这个 npm 包里的所有文件代码都是没有副作用的
"files": [ // 开发者引用该包后node_modules包里面的文件
"lib",
"README.md"
],
"keywords": [
"typescript",
"utils-demo",
"utils"
],
"scripts": {
"pub": "npm publish"
},
登陆 npm ,你会看到自己的 packages 里面有了刚刚发布的工具库包:
以上就是作者整理的从0到1构建基于自身业务的前端工具库的全过程,希望能给阅读本文的开发人员带来一些新的想法与尝试.
在此基础上已经成功在京东npm源发布了应用于京东汽车前端的工具库 @jdcar/car-utils ,并在各个业务线及系统得到落地.
当然,架构优化之路也还远未结束,比如:打包构建的速度、本地开发按需构建、工具库脚手架化等,后续我们也会基于自身业务以及一些新技术,持续深入优化,在性能上进一步提升,在功能上进一步丰富。本文或存在一些浅显不足之处,也欢迎大家评论指点.
[1] rollup 英文文档( https://rollupjs.org/guide/en/#quick-start ) 。
[2] rollup 中文文档( https://rollupjs.org/guide/zh/#introduction ) 。
[3] Rollup.js 实战学习笔记( https://chenshenhai.github.io/rollupjs-note/ ) 。
[4] Rollup 打包工具的使用( https://juejin.cn/post/6844904058394771470 ) 。
[5] TypeScript、Rollup 搭建工具库( https://juejin.cn/post/6844904035309322254 ) 。
[6] 使用 rollup.js 封装各项目共用的工具包( https://juejin.cn/post/6993720790046736420 ) 。
[7] 如何开发一个基于 TypeScript 的工具库并自动生成文档( https://juejin.cn/post/6844903881030238221 ) 。
[8] 一款优雅、简洁的 JavaScript 测试框架( https://jestjs.io/zh-Hans/ ) 。
最后此篇关于从0到1构建基于自身业务的前端工具库的文章就讲到这里了,如果你想了解更多关于从0到1构建基于自身业务的前端工具库的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
Java 库和 android 库有什么区别,各自有什么优点/缺点? 最佳答案 您可以在 Android 应用程序中包含标准 Java .jar 文件库。它们在 .apk 构建时被翻译成 Dalvik
所以,我现在的代码就像从 Java 层加载库(比如 liba.so),并在内部 liba.so 加载 libb.so。因此,如果我必须将所有库打包到 APK 中并将其安装在没有 root 访问权限的设
我想在我的系统中设置 LEDA 库。 我已经从以下链接下载了 LEDA 库 http://www.algorithmic-solutions.info/free/d5.php Instruct
我想用 autoconf 创建一个共享库。但是,我希望共享库具有“.so”扩展名,而不是以“lib”开头。基本上,我想制作一个加载 dlopen 的插件。 .是否有捷径可寻? 当我尝试使用 autoc
我需要在 Apps 脚本应用程序上修改 PDF。为此,我想使用 JS 库:PDF-LIB 我的代码: eval(UrlFetchApp.fetch("https://unpkg.com/pdf-lib
我正在构建一个使用以下 Boost header 的程序(我使用的是 Microsoft Visual C++ 10), #include #include #include #include
当我通过 cygwin 在 hadoop 上运行此命令时: $bin/hadoop jar hadoop-examples-*.jar grep input output 'dfs[a-z.]+' 我
我已经通过 vcpgk 成功安装了一个 C++ 库,名为:lmdb:x64-windows 我还安装了lmdb通过 Cabal 安装的 Haskell 绑定(bind)包 在尝试测试 lmdb 包时:
我该如何解决这个问题? 我刚刚将 javacv jar 文件复制到我的项目 Lib 文件夹下,但出现了这个错误! 我可以找到这个thread来自谷歌,但不幸的是,由于我国的谷歌限制政策,该页面无法打开
我有一个 Android 库项目 FooLib。 FooLib 引用 Android Context 之类的东西,但不需要任何资源文件(res/ 中的东西)所以我目前将其打包为供我的应用使用的 JAR
我正在开发一个 Android 应用程序(使用 Android Studio),它能够通过手势识别算法了解您正在进行的 Activity 。对于我使用 nickgillian ithub 帐户上可用的
关于从 .NET Framework 项目中引用 .NET Standard 类库的问题有很多类似的问题,其中 netstandard 库中的 NuGet 包依赖项不会流向 netframework
我已经从互联网上下载了 jna-4.2.2.jar,现在想将这个 jar 导入到我的项目中。但是当我试图将这个 jar 导入我的项目时,出现以下错误。 [2016-06-20 09:35:01 - F
我正在尝试通过编译在 Mac 上安装 rsync 3.2.3。但是,我想安装所有功能。为此,它需要一些库,此处 ( https://download.samba.org/pub/rsync/INSTA
进入 Web 开发有点困难。过去 5 年我一直致力于 winforms 工作。所以我正在努力从一种切换到另一种。前段时间,我使用过 JavaScript,但现在还没有大量的 JavaScript 库
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
我正在寻找一个用Python编写的与logstash(ruby + java)类似的工具/库。 我的目标是: 从 syslog 中解析所有系统日志 解析应用程序特定日志(apache、django、m
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
我花了几天时间试图寻找用于 JavaPOS 实现的 .jar 库,但我找不到任何可以工作的东西。我找到了很多像这样的文档:http://jpos.1045706.n5.nabble.com/file/
这个问题在这里已经有了答案: Merge multiple .so shared libraries (2 个答案) 关闭 9 年前。 我有我在代码中使用的第三方库的源代码和对象。该库附带有关如何使
我是一名优秀的程序员,十分优秀!