3分钟精通高阶前端随手写TS插件

目录
  • 正文
  • 什么是Rollup?
  • 为何要做脚手架?
  • 它能干啥?
  • 起锅-安装
  • 大火-配置
    • 创建目录
    • 配置rollup
    • 配置ESlint
    • TS编译配置
    • 配置Babel
  • Demo
  • 出锅-跑一跑
  • 最后Package.json
  • 总结

正文

随着业务复杂度和技术深度的增加,有时我们不得不提高抽离插件的效率。尽管有很多的技术方案,但总是夹杂了很多依赖和类库,总感觉没那么纯净。因此,在某个如厕的瞬间,萌发了一种可以酣畅淋漓写插件的姿势。

脚手架,就能应当根据个人爱好和编码习惯来灵活配置。 下面我们就来一层一层的剖析。算了,一层一层太慢你们也没耐心,直接剖。

什么是Rollup?

Rollup是一款集成式的代码打包、应用构建工具。扒拉扒拉文档

为何要做脚手架?

如上面啰嗦的,前端工程化是作为工程师的必要能力,工程化并非一个人就能搞定的,我们需要站在前人/巨人(Copy)的肩膀看世界。

随着技术的发展,涌现了一些最佳实践的构建工具,这些构建工具将一些项目管理和编程开发的行业最佳实践集成到了一个“脚手架”工具中。如此,便有利于其他团队快速构建出高效、高质量的工程化项目。

它能干啥?

构建工具能做的事:

  • 处理兼容性
  • 混淆、压缩代码
  • Tree Shaking
  • 转译
  • 单元测试
  • 打包应用

起锅-安装

yarn add rollup -g

个人推荐使用pnpm

// 安装pnpm
npm install -g pnpm
// 安装rollup
pnpm add rollup -g

大火-配置

使用rollup打包构建有两种方式,直接在命令行下需要手打构建必须的参数,当然我们是做工程,那么就得考虑如何尽可能减少团队成员的上手成本。

创建目录

|-- src                       //开发文件夹
  |   |-- index.ts            //入口文件
|-- rollup.config.js          //rollup配置文件
|-- index.ts                  //对外暴露统一入口(非必须)

配置rollup

根目录下创建一个纯净且功能强大rollup.config.js配置文件,可以优先了解下各类插件的机制,后面会提供一个package.json,直接安装就齐活了。

import path from 'path';
import ts from 'rollup-plugin-typescript2';
// 将json 文件转换为ES6 模块
import json from '@rollup/plugin-json';
// 在node_模块中查找并绑定第三方依赖项
import resolve from '@rollup/plugin-node-resolve';
// 将CommonJS模块转换为ES6
import commonjs from '@rollup/plugin-commonjs';
// rollup babel插件
import babel from 'rollup-plugin-babel';
// 优化代码压缩
import { terser } from 'rollup-plugin-terser';
// 加载样式文件
import styles from 'rollup-plugin-styles';
// 代码检查
import { eslint } from "rollup-plugin-eslint";
import dts from 'rollup-plugin-dts';
// 热更新服务
import livereload from 'rollup-plugin-livereload';
// 开发服务器
import serve from 'rollup-plugin-serve';
// 清除目录工具
import clear from "rollup-plugin-clear";
import pkg from './package.json';
// 判断是开发环境or生产环境
const NODE_ENV = process.env.NODE_ENV;
const isPro = function () {
  return NODE_ENV === 'production';
};
// 编译支持的文件类型
const extensions = ['.js', '.jsx', '.ts', '.tsx', '.less'];
export default [
  {
    input: path.resolve('./index.ts'),
    output: [
      {
        file: pkg.unpkg,
        format: 'umd',
        name: '插件方法名',
        sourcemap: true,
      },
      {
        file: pkg.module,
        format: 'esm',
        sourcemap: true,
      },
      {
        file: pkg.main,
        format: 'cjs',
        sourcemap: true,
      },
    ],
    plugins: [
      resolve(),
      commonjs(),
      json(),
      styles(),
      eslint(), // 这里没传入配置参数,会自动加载文件根目录的 `.eslintrc.json` 配置文件。
      ts({
        tsconfig: path.resolve(__dirname, './tsconfig.json'),
        extensions: extensions,
      }),
      babel({
        runtimeHelpers: true,
        exclude: 'node_modules/**',
      }),
      !isPro() &&
        livereload({
          watch: ['dist', 'examples', 'src/**'],
          verbose: false,
        }),
      isPro() && terser(),
      !isPro() &&
        serve({
          headers: { "Access-Control-Allow-Origin": "*", // 本地服务允许跨域 },
          open: false,
          port: 9529,
          contentBase: './', // 本地服务的运行文件根目录
          openPage: '/examples/index.html',
        }),
    ],
  },
  {
    // 生成 .d.ts 类型声明文件
    input: path.resolve('./index.ts'),
    output: {
      file: pkg.types,
      format: 'es',
    },
    plugins: [
      dts(),
      clear({ targets: ["dist/src"], // 项目打包编译生成的目录
      watch: true, // 实时监听文件变化 })
    ],
  },
];

提供自查配置列表:https://www.rollupjs.com/guide/big-list-of-options

配置ESlint

废话介绍ESLint 是在 ES/JS代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误

通过ESlint可以尽可能地规范团队开发的代码风格以及通过静态检查提升代码质量。扒拉扒拉文档 安装eslint

pnpm add eslint -D

初始化,参数可按照心情选择

pnpm run eslint --init

初始化完成后,在根目录创建了一个ESlint的配置文件:.eslintrc.json

{
    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "standard"
    ],
    "parserOptions": {
        "ecmaVersion": 12,
        "sourceType":
            "module"
        },
    "rules": { }
}

新建.eslintignore 文件来忽略不需要Eslint检查的内容

/dist/
/public/
/rollup.config.js

配置rollup支持ESlint,ps:上面已经支持了

import { eslint } from "rollup-plugin-eslint";
···
eslint();
···

TS编译配置

根目录创建tsconfig.json文件,设置编译参数

{
  "compilerOptions": {
    "target": "es6", // 编译后的es版本
    "module": "esnext", // 前端模块化规范
    "allowJs": true, // 允许引入js文件
    "strict": true, // 开启严格模式
    "importHelpers": true,
    "moduleResolution": "node",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "suppressImplicitAnyIndexErrors": true,
    "resolveJsonModule": true,
    "sourceMap": true,
    "declaration": true,
    "lib": ["esnext", "DOM"]
  },
  "exclude": ["node_modules/**"]
}

配置Babel

这个就很简单了,直接提供文档自己扒拉扒拉,就两句话一定要去看。

// .babelrc
{
  "presets": ["@babel/preset-env", "@babel/preset-typescript"]
}

Demo

为了能够快速测试插件的调用,又避免引入Vue、React等框架。使用最新浏览器支持的ESM方式加载打包后的插件,并启动服务快速调试,下面我们搞一搞。 根目录下创建examples文件夹,并新建index.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Demo</title>
    <script src="../dist/index.umd.js"></script>
</head>
<body>
    <h1 align="center" id="app">Hello 我是扫地盲僧!</h1>
    <p align="center" id="content"></p>
</body>
<script>
    const demo = new tsClass('Hello rollup', null, '这是一个基于rollup打包TypeScript的纯净框架')
    const h1 = document.querySelector('#app')
    const p = document.querySelector('#content')
    h1.innerHTML = demo.name
    p.innerHTML = demo.content
</script>

出锅-跑一跑

// 运行起来试一试
pnpm run dev

ok搞定,很复杂吗?不复杂!!

最后Package.json

可以根据自己需求随机删减,学会灵活使用

{
    "name": "rollup-ts-tpl",
    "version": "1.1.1",
    "description": "一个纯净版的ts插件打包cli",
    "main": "dist/index.cjs.js",
    "module": "dist/index.esm.js",
    "unpkg": "dist/index.umd.js",
    "jsdelivr": "dist/index.umd.js",
    "types": "dist/index.d.ts",
    "scripts": {
        "dev": "cross-env ENV=dev rollup -c -w",
        "build": "cross-env ENV=production rimraf dist && rollup -c"
    },
    "author": "扫地盲僧",
    "license": "MIT",
    "devDependencies": {
        "@babel/core": "^7.12.3",
        "@babel/plugin-transform-runtime": "^7.16.4",
        "@babel/preset-env": "^7.12.1",
        "@babel/runtime": "^7.16.3",
        "@rollup/plugin-commonjs": "^16.0.0",
        "@rollup/plugin-eslint": "^8.0.1",
        "@rollup/plugin-json": "^4.1.0",
        "@rollup/plugin-node-resolve": "^10.0.0",
        "@rollup/plugin-typescript": "^6.1.0",
        "@typescript-eslint/parser": "^4.14.0",
        "@types/node": "^17.0.31",
        "cross-env": "^7.0.3",
        "babel-plugin-external-helpers": "^6.22.0",
        "babel-preset-latest": "^6.24.1",
        "eslint": "^7.18.0",
        "less": "^4.1.2",
        "rollup": "^2.33.1",
        "rollup-plugin-babel": "^4.4.0",
        "rollup-plugin-clear": "^2.0.0",
        "rollup-plugin-dts": "^3.0.2",
        "rollup-plugin-livereload": "^2.0.0",
        "rollup-plugin-serve": "^1.1.0",
        "rollup-plugin-terser": "^7.0.2",
        "rollup-plugin-typescript2": "^0.30.0",
        "tslib": "^2.3.1",
        "typescript": "^4.0.5"
    }
}

总结

Rollup打包工具的基本使用就差不多了,通过尝试可以发现,Rollup的配置等是非常简单的,改变了开发者的工作形式,以及提升了工作(编码)效率

这里我就不贴仓库了,无脑copy倒不如自己按照文档写一遍,又能加深记忆也可快速掌握原理。3分钟让你使用大佬们惯用的姿势。

自然者,物见其然,不知所以然;同焉皆得,不知所以得”。 作为前端工程师,我们不仅是要会用,还要明白构建的整个过程,这有助于我们在编码、架构设计上能够更加合理,或者说更“自然”。

以上就是3分钟精通高阶前端随手写TS插件的详细内容,更多关于前端手写TS插件的资料请关注我们其它相关文章!

(0)

相关推荐

  • TypeScript利用TS封装Axios实战

    目录 简介 Axios几个常用类型 AxiosRequestConfig AxiosInstance AxiosStatic AxiosResponse AxiosError 基础封装 拦截器封装 常用方法封装 总结 简介 这是TypeScript实战的第三篇文章.前面两篇笔者分别介绍了在Vuex和Pinia中怎么使用TypeScript以及Vuex和Pinia的区别.今天我们再用TypeScript封装一遍Axios.希望能进一步巩固TypeScript的基础知识. Axios几个常用类型 在

  • 详解TypeScript+Vue 插件 vue-class-component的使用总结

    首先 下载 npm install vue-class-component vue-property-decorator --save-dev 一梭子直接干: 其次,咱来说说它们的区别与联系: vue-property-decorator社区出品:vue-class-component官方出品 vue-class-component提供了Vue.Component等: vue-property-decorator深度依赖了vue-class-component,拓展出了更多操作符:@Prop.@

  • TypeScript Pinia实战分享(Vuex和Pinia对比梳理总结)

    目录 简介 安装 创建pinia并传递给vue实例 创建store state getters actions 在vue组件使用 获取state 获取getters 修改state 数据持久化 总结 简介 今天我们再来实战下官方推荐的新的vue状态管理工具Pinia. pinia 由 vue 团队中成员所开发的,因此也被认为是下一代的 vuex,即 vuex5.x,在 vue3 的项目中使用也是备受推崇.所以 pinia 的学习迫在眉睫. 下面我们正式开始pinia的学习吧. 安装 yarn a

  • Typescript中使用引用路径别名报错的解决方法

    在TS中引用路径别名提示找不到模块或者相应的声明 1.ts中使用路径别名报错 在react中通常路径别名都是在webpack的webpack.config.js文件中配置的,但是在引入了ts之后,webpack中的路径别名引用失效了此时我们需要在跟src文件同级目录的tsconfig.json文件中添加配置: 注意要在compilerOptions中添加(webpack中的路径也需要配置) "compilerOptions": { "target": "e

  • typescript+vite项目配置别名的方法实现

    我们为了省略冗长的路径,经常喜欢配置路径别名.但是在typescript下会遇到一些坑,比如导入路径不能以“.ts”扩展名结束,路径不识别等.下面我记录了我的处理方法. vite.config.js: export default defineConfig({   resolve: {     alias: {       '@': path.resolve(__dirname, 'src') // 配置别名     }   } }) 配置完之后,就可以在ide中使用别名了.但是这个时候我发现,

  • vue3+typescript实现图片懒加载插件

    github项目地址: github.com/murongg/vue- 求star 与 issues 我文采不好,可能写的文章不咋样,有什么问题可以在留言区评论,我会尽力解答 本项目已经发布到npm 安装: $ npm i vue3-lazyload # or $ yarn add vue3-lazyload 需求分析 支持自定义 loading 图片,图片加载状态时使用此图片 支持自定义 error 图片,图片加载失败后使用此图片 支持 lifecycle hooks,类似于 vue 的生命周

  • 3分钟精通高阶前端随手写TS插件

    目录 正文 什么是Rollup? 为何要做脚手架? 它能干啥? 起锅-安装 大火-配置 创建目录 配置rollup 配置ESlint TS编译配置 配置Babel Demo 出锅-跑一跑 最后Package.json 总结 正文 随着业务复杂度和技术深度的增加,有时我们不得不提高抽离插件的效率.尽管有很多的技术方案,但总是夹杂了很多依赖和类库,总感觉没那么纯净.因此,在某个如厕的瞬间,萌发了一种可以酣畅淋漓写插件的姿势. 脚手架,就能应当根据个人爱好和编码习惯来灵活配置. 下面我们就来一层一层的

  • React组件重构之嵌套+继承及高阶组件详解

    前言 在最近做的一个react项目中,遇到了一个比较典型的需要重构的场景:提取两个组件中共同的部分. 最开始通过使用嵌套组件和继承的方式完成了这次重构. 但是后来又用高阶组件重新写了一遍,发现更好一点. 在这里记录下这两种方式以便之后参考和演进. 本次重构的场景 因为场景涉及到具体的业务,所以我现在将它简化为一个简单的场景. 现在有两个黑色箱子,箱子上都有一个红色按钮,A箱子充满气体,按了按钮之后箱子里面气体变红,B箱子充满泥土,按了之后箱子里面泥土变红. 那么现在上一个简单的重构前代码: Bo

  • 详解Go语言如何利用高阶函数写出优雅的代码

    目录 前言 问题 白银 黄金 王者 总结 前言 go项目中经常需要查询db,按照以前java开发经验,会根据查询条件写很多方法,如: GetUserByUserID GetUsersByName GetUsersByAge 每一种查询条件写一个方法,这种方式对外是挺好的,对外遵循严格原则,让每个对外的方法接口是明确的.但是对内的话,应该尽可能的通用,做到代码复用,少写代码,让代码看起来更优雅.整洁. 问题 在review代码的时候,针对上面3个方法,一般写法是 func GetUserByUse

  • 30分钟精通React今年最劲爆的新特性——React Hooks

    你还在为该使用无状态组件(Function)还是有状态组件(Class)而烦恼吗? --拥有了hooks,你再也不需要写Class了,你的所有组件都将是Function. 你还在为搞不清使用哪个生命周期钩子函数而日夜难眠吗? --拥有了Hooks,生命周期钩子函数可以先丢一边了. 你在还在为组件中的this指向而晕头转向吗? --既然Class都丢掉了,哪里还有this?你的人生第一次不再需要面对this. 这样看来,说React Hooks是今年最劲爆的新特性真的毫不夸张.如果你也对react

  • Java十分钟精通集合的使用与原理下篇

    List集合: ArrayList: 底层是数组结构,储存有序并且可以重复的对象 package SetTest; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ArrayListTest { public static void main(String[] args) { //创建ArrayList的对象 List<Integer> list = ne

  • Java十分钟精通泛型的使用与原理

    什么是泛型? 简而言之:<>泛型就是用来约束类.方法.属性上的数据类型,比如 List<Integer> list = new ArrayList<Integer>(); new ArrayList这个集合的元素只能添加Integer类型. 为什么需要泛型? Java推出泛型之前,程序员可以构建一个Object类型的集合,该集合能够存储任何的数据类型,而在使用该 集合的时候,需要程序员明确知道每个元素的具体的类型并向下转型,否则容易引发ClassCastExceptio

  • SprinBoot如何集成参数校验Validator及参数校验的高阶技巧

    目录 为什么需要参数校验 SpringBoot中集成参数校验 第一步,引入依赖 第二步,定义要参数校验的实体类 第三步,定义校验类进行测试 第四步,体验效果 参数异常加入全局异常处理器 体验效果 自定义参数校验 第一步,创建自定义注解 第二步,自定义校验逻辑 第三步,在字段上增加注解 第四步,体验效果 分组校验 第一步:定义分组接口 第二步,在模型中给参数分配分组 第三步,给需要参数校验的方法指定分组 第四步,体验效果 小结 前几天写了一篇<SpringBoot如何统一后端返回格式?老鸟们都是这

  • 从柯里化分析JavaScript重要的高阶函数实例

    目录 前情回顾 百变柯里化 缓存传参 缓存判断 缓存计算 缓存函数 防抖与节流 lodash 高阶函数 结语 前情回顾 我们在前篇 <从历史讲起,JavaScript 基因里写着函数式编程> 讲到了 JavaScript 的函数式基因最早可追溯到 1930 年的 lambda 运算,这个时间比第一台计算机诞生的时间都还要早十几年.JavaScript 闭包的概念也来源于 lambda 运算中变量的被绑定关系. 因为在 lambda 演算的设定中,参数只能是一个,所以通过柯里化的天才想法来实现接

  • 详谈Python高阶函数与函数装饰器(推荐)

    一.上节回顾 Python2与Python3字符编码问题,不管你是初学者还是已经对Python的项目了如指掌了,都会犯一些编码上面的错误.我在这里简单归纳Python3和Python2各自的区别. 首先是Python3-->代码文件都是用utf-8来解释的.将代码和文件读到内存中就变成了Unicode,这也就是为什么Python只有encode没有decode了,因为内存中都将字符编码变成了Unicode,而Unicode是万国码,可以"翻译"所以格式编码的格式.Python3中

  • iOS 10 推送高阶篇(必看)

    推荐阅读: iOS10推送之基础知识(必看篇) 这篇文章开始,我会跟大家好好讲讲,苹果新发布的iOS10的所有通知类. 一.创建本地通知事例详解: 注意啊,小伙伴们,本地通知也必须在appdelegate中注册中心,通知的开关打不打开无所谓的,毕竟是本地通知,但是通知的接收的代理,以及通知点击的代理,苹果给合二为一了.所以大家还是需要在appdelegate中写上这2个方法,还有不要忘记在- (BOOL)application:(UIApplication *)application didFi

随机推荐