沐游虞笔记
  • 前端面试题

    • HTML面试题汇总(无答案)
    • HTML面试题汇总
    • CSS 面试题汇总(无答案)
    • CSS 面试题汇总
    • javascript 面试题汇总(无答案)
    • javascript 面试题汇总
    • promise 面试题(无答案)
    • promise 面试题
    • 浏览器面试题汇总(无答案)
    • 浏览器面试题汇总
    • 网络面试题汇总(无答案)
    • 网络面试题汇总
    • 工程化面试题汇总(无答案)
    • 工程化面试题汇总
    • VUE面试题汇总(无答案)
    • VUE面试题汇总
  • 直播课文件

    • 静态页面学习指导
    • 属性的计算过程
    • 层叠继承规则总结
    • BFC
    • JS基础知识回顾
    • DOM 事件的传播机制
    • DOM 事件的注册和移除
    • 阻止事件默认行为
    • 基础领航考试题
    • 基础领航考试题(答案)
    • 2024前端发展
    • JS核心概念学习指导
    • 第三方库与工程化学习指导
    • Vue入门学习指导
    • vue进阶学习指导
    • 前端性能优化
  • 笔面试环节知识讲解

    • 目录
    • 图像处理
    • 图像处理(面试)
    • Webpack构建优化
    • Webpack构建优化(面试)
    • TTS性能优化
    • TTS性能优化(面试)
    • 实时协作
    • 实时协作(面试)
    • 网页复制图片到剪贴板
    • 网页复制图片到剪贴板(面试)
    • vite插件
    • vite插件(面试)
    • 表单数据同步与保持
    • 表单数据同步与保持(面试)
    • 优化虚拟列表
    • 优化虚拟列表(面试)
    • 微前端解决巨石应用
    • 微前端解决巨石应用(面试)
    • DNS解析与优化
    • DNS解析与优化(面试)
    • 前端监控
    • 前端监控(面试)
    • 12.跨标签页通信
    • 12.跨标签页通信(面试)
    • 13.Vite相关优化
    • 13.Vite相关优化(面试)
    • 14.计时器节流问题
    • 14.计时器节流问题(面试)
    • 15.多文件预览支持
    • 15.多文件预览支持(面试)
    • 16.defer优化白屏时间
    • 16.defer优化白屏时间(面试)
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
  • 图解快速dff
  • 最长递增子序列
  • 模板编译器
  • 模板编译提升
  • 组件name作用
  • 路由传参方式
  • 基础篇

    • 序章React介绍
    • JSX基础语法
    • React基本介绍
    • 表单
    • 生命周期
    • 组件与事件绑定
    • 组件状态与数据传递
    • Hooks
    • React--redux介绍
    • React-router介绍
  • 就业篇

    • 属性默认值和类型验证
    • 高阶组件
    • Ref
    • Context
    • Render Props
    • Portals
    • 错误边界
    • 组件渲染性能优化
    • 前端框架的理解
    • Reacti和Vue描述页面的区别
    • 前端框架的分类
    • 虚拟DoM
    • React整体架构
    • React渲染流程
    • Fiber双缓冲
    • MessageChannel
    • Scheduleri调度普通任务
    • Scheduleri调度延时任务
    • 最小堆
    • React中的位运算
    • beginWork工作流程
    • completeWork工作流程
    • 图解diff算法
    • commit工作流程
    • lane模型
    • React中的事件
    • Hooks原理
    • useStateuseReducer.
    • effect相关hook
    • useCallbackuseMemo
    • useRef
    • Update
    • 性能优化策略之eagerState
    • 性能优化策略之bailout
    • bailoutContextAPl
    • 性能优化对日常开发启示
  • 前端监控概述
  • 错误监控
  • 数据上报
  • 页面性能监控
  • 用户行为收集与埋点
  • CSS3手册
  • HTML5手册
  • JavaScript语言提升

    • es补充
    • 事件循环
    • promise基础
    • Promise的链式调用
    • Promise的静态方法
    • async和await
    • Promise相关面试题
  • 网络

    • 客户端与服务器
    • 关于 Apifox 的使用
  • git文档
  • 工程化

    • CommonJS
    • ES module
    • npm文档(包管理)
    • Lass笔记
    • webpack工具
  • canvas详解
  • uinapp笔记
  • 自动化测试
  • oauth2令牌

    • 认识Oauth2
    • 三方应用实现github授权
    • 微信三方应用登录实现
    • 支付宝沙箱支付功能
  • 前端面试题

    • HTML面试题汇总(无答案)
    • HTML面试题汇总
    • CSS 面试题汇总(无答案)
    • CSS 面试题汇总
    • javascript 面试题汇总(无答案)
    • javascript 面试题汇总
    • promise 面试题(无答案)
    • promise 面试题
    • 浏览器面试题汇总(无答案)
    • 浏览器面试题汇总
    • 网络面试题汇总(无答案)
    • 网络面试题汇总
    • 工程化面试题汇总(无答案)
    • 工程化面试题汇总
    • VUE面试题汇总(无答案)
    • VUE面试题汇总
  • 直播课文件

    • 静态页面学习指导
    • 属性的计算过程
    • 层叠继承规则总结
    • BFC
    • JS基础知识回顾
    • DOM 事件的传播机制
    • DOM 事件的注册和移除
    • 阻止事件默认行为
    • 基础领航考试题
    • 基础领航考试题(答案)
    • 2024前端发展
    • JS核心概念学习指导
    • 第三方库与工程化学习指导
    • Vue入门学习指导
    • vue进阶学习指导
    • 前端性能优化
  • 笔面试环节知识讲解

    • 目录
    • 图像处理
    • 图像处理(面试)
    • Webpack构建优化
    • Webpack构建优化(面试)
    • TTS性能优化
    • TTS性能优化(面试)
    • 实时协作
    • 实时协作(面试)
    • 网页复制图片到剪贴板
    • 网页复制图片到剪贴板(面试)
    • vite插件
    • vite插件(面试)
    • 表单数据同步与保持
    • 表单数据同步与保持(面试)
    • 优化虚拟列表
    • 优化虚拟列表(面试)
    • 微前端解决巨石应用
    • 微前端解决巨石应用(面试)
    • DNS解析与优化
    • DNS解析与优化(面试)
    • 前端监控
    • 前端监控(面试)
    • 12.跨标签页通信
    • 12.跨标签页通信(面试)
    • 13.Vite相关优化
    • 13.Vite相关优化(面试)
    • 14.计时器节流问题
    • 14.计时器节流问题(面试)
    • 15.多文件预览支持
    • 15.多文件预览支持(面试)
    • 16.defer优化白屏时间
    • 16.defer优化白屏时间(面试)
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
  • 图解快速dff
  • 最长递增子序列
  • 模板编译器
  • 模板编译提升
  • 组件name作用
  • 路由传参方式
  • 基础篇

    • 序章React介绍
    • JSX基础语法
    • React基本介绍
    • 表单
    • 生命周期
    • 组件与事件绑定
    • 组件状态与数据传递
    • Hooks
    • React--redux介绍
    • React-router介绍
  • 就业篇

    • 属性默认值和类型验证
    • 高阶组件
    • Ref
    • Context
    • Render Props
    • Portals
    • 错误边界
    • 组件渲染性能优化
    • 前端框架的理解
    • Reacti和Vue描述页面的区别
    • 前端框架的分类
    • 虚拟DoM
    • React整体架构
    • React渲染流程
    • Fiber双缓冲
    • MessageChannel
    • Scheduleri调度普通任务
    • Scheduleri调度延时任务
    • 最小堆
    • React中的位运算
    • beginWork工作流程
    • completeWork工作流程
    • 图解diff算法
    • commit工作流程
    • lane模型
    • React中的事件
    • Hooks原理
    • useStateuseReducer.
    • effect相关hook
    • useCallbackuseMemo
    • useRef
    • Update
    • 性能优化策略之eagerState
    • 性能优化策略之bailout
    • bailoutContextAPl
    • 性能优化对日常开发启示
  • 前端监控概述
  • 错误监控
  • 数据上报
  • 页面性能监控
  • 用户行为收集与埋点
  • CSS3手册
  • HTML5手册
  • JavaScript语言提升

    • es补充
    • 事件循环
    • promise基础
    • Promise的链式调用
    • Promise的静态方法
    • async和await
    • Promise相关面试题
  • 网络

    • 客户端与服务器
    • 关于 Apifox 的使用
  • git文档
  • 工程化

    • CommonJS
    • ES module
    • npm文档(包管理)
    • Lass笔记
    • webpack工具
  • canvas详解
  • uinapp笔记
  • 自动化测试
  • oauth2令牌

    • 认识Oauth2
    • 三方应用实现github授权
    • 微信三方应用登录实现
    • 支付宝沙箱支付功能
  • 必看导言

    • 就业的核心问题

      • 课件
    • 表现力的训练

      • 课件
  • 简历制作

    • 课件
    • 简历准备课堂笔记
    • 个人信息课堂笔记
    • 求职意向课堂笔记
    • 技术栈课堂笔记
    • 教育经历课堂笔记
    • 个人优势与评价课堂笔记
    • 工作经历课堂笔记
    • 项目
    • 项目亮难点问题

    • 项目经历

  • 项目准备

    • 课件
    • 课件
  • 技术重点

    • 划重点

    • 非技术环节
  • 简历投递和面试准备

    • 简历投递
    • 面试准备
  • 笔面试环节知识讲解
  • 项目准备
  • 难点攻关
  • 表单数据同步与保持
  • 课件资料
luzhichang
2024-09-18
目录

07-技术讲解

# 公共表单模块技术讲解

# 什么问题

大型的管理系统,表单页的内容也会非常的多。

  1. 数据丢失风险
  2. 表单数据恢复
  3. 跨标签页通信
  4. 去除本地冗余数据

将核心功能逻辑封装成公共模块,同时在 Vue 和 React 中使用

# 解决思路

  1. 抽离一个类出来。在类中实现:

    1. 将当前表单数据保存到 localStorage
    2. 从 localStorage 加载数据并同步到表单数据
    3. 通过 BroadcastChannel 广播数据
    4. 清除本地的数据
    5. 各种细节处理
  2. 发布前的准备工作。

    • 代码测试
    • 代码的丑化和压缩
  3. 发布到 npm 上面。

# 解决细节

# 1. 封装类

  • FormStorage:负责主要的功能实现
    • 数据存储、加载、更新、清除
    • 函数防抖
    • 数据广播
  • FormStorageManager:负责在第一次初始化的时候注册事件。

# 2. 测试

使用 Vitest 对 FormStorage 做单元测试。

首先第一步安装 Vitest:

npm install --save-dev vitest @testing-library/react @testing-library/jest-dom

接下来创建 vitest.config.js 文件:

/// <reference types="vitest" />

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './vitest.setup.js',
  },
});

在根目录下创建一个 vitest.setup.js 文件,用于设置 Vitest 的初始配置:

import '@testing-library/jest-dom';

然后在 utils 文件夹中创建一个 FormStorage.test.js 文件:

import { describe, it, expect, beforeEach, vi } from 'vitest';
import FormStorage from './FormStorage';

// 模拟 BroadcastChannel
// 由于 Vitest 不支持 BroadcastChannel,所以我们需要创建一个全局的 BroadcastChannel 模拟对象。
global.BroadcastChannel = class {
  constructor(name) {
    this.name = name;
    this.onmessage = null;
  }
  postMessage(message) {
    if (this.onmessage) {
      this.onmessage({ data: message });
    }
  }
  close() {}
};

describe('FormStorage', () => {
  let formData;

  // 在每个测试之前清除 localStorage 并重置表单数据。
  beforeEach(() => {
    formData = { value: { username: '', gender: 'secret' } };
    localStorage.clear();
  });

  // 书写各种测试用例
  
  it('初始化测试', () => {
    // 测试 init 方法是否正确从 localStorage 加载数据。
    localStorage.setItem('formData_page1Form', JSON.stringify({ username: '张三', gender: 'male' }));
    const formStorage = new FormStorage('page1Form', formData);
    formStorage.init();
    expect(formData.value).toEqual({ username: 'John', gender: 'male' });
  });

  it('保存数据测试', () => {
    // 测试 saveData 方法是否正确保存数据到 localStorage
    const formStorage = new FormStorage('page1Form', formData);
    formData.value.username = 'John';
    formStorage.saveData();
    const savedData = JSON.parse(localStorage.getItem('formData_page1Form'));
    expect(savedData).toEqual({ username: 'John', gender: 'secret' });
  });

  // 更多测试用例...
});

最后添加一个 test 脚本到 package.json:

"scripts": {
  "test": "vitest"
}

然后运行测试跑这些测试用例即可:

npm run test

# 3. 压缩

使用 rollup 来做打包。rollup 有这么一些特点:

  1. Tree Shaking:可以自动去除未使用的代码。这对于公共库特别重要,因为它能够确保打包后的代码尽可能小,从而提高加载性能和使用效率。
  2. 输出格式多样:rollup 支持多种输出格式,例如 CommonJS、ESM、UMD 等。这使得一个库可以在不同的运行环境(Node.js、浏览器、模块打包器等)中使用,增加了库的兼容性和灵活性。
  3. 插件系统:rollup 提供了丰富的插件生态系统,可以方便地进行代码转换、压缩、文件处理等操作。例如,我使用了 @rollup/plugin-node-resolve 和 @rollup/plugin-commonjs 插件来处理模块解析和转换,并使用 rollup-plugin-terser 对代码进行压缩,确保生成的包体积尽可能小。
  4. 代码优化:rollup 能够对代码进行细粒度的优化,例如去除重复的依赖、压缩代码、内联代码等。这些优化能够显著减少打包后文件的大小,提高代码的执行效率。

首先仍然是安装依赖:

npm install --save-dev rollup rollup-plugin-terser @rollup/plugin-node-resolve @rollup/plugin-commonjs

然后在项目根目录下创建一个 rollup.config.js 的配置文件:

import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';

export default {
  input: 'src/utils/FormStorage.js', // 输入文件路径
  // 打包输出的不同格式
  output: [
    {
      file: 'dist/FormStorage.cjs.js', // CommonJS 产物路径
      format: 'cjs',
      sourcemap: true,
    },
    {
      file: 'dist/FormStorage.esm.js', // ES 模块产物路径
      format: 'esm',
      sourcemap: true,
    },
    {
      file: 'dist/FormStorage.umd.js', // UMD 产物路径
      format: 'umd',
      name: 'FormStorage',
      sourcemap: true,
    },
  ],
  plugins: [
    resolve(), // 使 Rollup 能够找到 node_modules 中的模块
    commonjs(), // 使 Rollup 能够转换 CommonJS 模块为 ES6
    terser(), // 压缩代码
  ],
};

之后更新 package.json,在该文件中定义入口文件路径:

{
  "name": "formstorage",
  "version": "1.0.0",
  "main": "dist/FormStorage.cjs.js", // CommonJS 入口
  "module": "dist/FormStorage.esm.js", // ES 模块入口
  "unpkg": "dist/FormStorage.umd.js", // UMD 入口
  "scripts": {
    "build": "rollup -c",
    "test": "vitest"
  },
  "devDependencies": {
    "rollup": "^2.42.4",
    "rollup-plugin-terser": "^7.0.2",
    "@rollup/plugin-node-resolve": "^13.0.6",
    "@rollup/plugin-commonjs": "^20.0.0",
    "vitest": "^0.0.127",
    "@testing-library/react": "^12.1.2",
    "@testing-library/jest-dom": "^5.16.3"
  }
}

最后运行 npm run build 进行打包。

# 4. npm 发布

打包完成后,整体的项目目录如下:

/vue-project
  ├── dist
  │   ├── FormStorage.cjs.js
  │   ├── FormStorage.esm.js
  │   └── FormStorage.umd.js
  ├── node_modules
  ├── public
  ├── src
  │   ├── assets
  │   ├── router
  │   ├── utils
  │   │   ├── FormStorage.js
  │   │   └── FormStorage.test.js
  │   ├── views
  │   ├── App.vue
  │   └── main.js
  ├── .eslintrc.cjs
  ├── .gitignore
  ├── .npmignore
  ├── .prettierrc.json
  ├── index.html
  ├── jsconfig.json
  ├── package-lock.json
  ├── package.json
  ├── README.md
  ├── rollup.config.js
  ├── vite.config.js
  └── vitest.setup.js

在发布到 npm 时,通常只发布打包后的 dist 目录和必要的配置文件,以减小包的体积并确保用户能够正确使用你的库。

这里有两种方式:

  1. 白名单

在 package.json 文件中配置 files 字段,如下所示:

{
  "name": "formstorage",
  "version": "1.0.0",
  "main": "dist/FormStorage.cjs.js",
  "module": "dist/FormStorage.esm.js",
  "unpkg": "dist/FormStorage.umd.js",
  "scripts": {
    "build": "rollup -c",
    "test": "vitest"
  },
  "files": [
    "dist"
  ],
  // ...
}

只有 files 字段对应的目录和文件才会被上传至 npm

  1. 黑名单

在项目根目录下创建一个 .npmignore 文件,用于排除不需要的文件和目录:

/src
/public
/node_modules
/rollup.config.js
/vitest.setup.js
/vitest.config.js
.eslintrc.cjs
.prettierrc.json
jsconfig.json
vite.config.js

推荐使用白名单的方式,因为黑名单每次新增文件或目录后都需要更新 .npmignore 文件。

最后登录 npm,然后使用 npm publish 进行包的发布即可。


-EOF-

Theme by Vdoing | Copyright © 2021-2024 蜀ICP备2024068710号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式