Chart.js 集成指南:Script Tag、Bundler Tree-Shaking、CommonJS 与 RequireJS 四种加载方式详解
【免费下载链接】Chart.jsSimple HTML5 Charts using the项目地址: https://gitcode.com/gh_mirrors/ch/Chart.js
本文基于 Chart.js 官方文档 docs/getting-started/integration.md 展开,系统讲解 Chart.js 在脚本标签、模块打包器(Webpack/Rollup 等)、CommonJS 与 RequireJS 环境下的完整集成方法,并结合仓库源码剖析chart.js/auto自动注册包、组件注册表(Registry)与chart.js/helpers工具包的实现机制。读完本文,你可以为任意前端项目选择最合适的集成路径,并按需在“功能完整”与“包体最小”之间做出取舍。
集成方式总览:先看发布产物
Chart.js 是纯 ESM 库,package.json中声明了"type": "module",并通过exports字段暴露三个入口:
chart.js:主入口,ESM 产物为dist/chart.js,CommonJS 产物为dist/chart.cjs;chart.js/auto:自动注册包,ESM 产物auto/auto.js,CJS 产物auto/auto.cjs;chart.js/helpers:独立工具函数包,ESM 产物helpers/helpers.js,CJS 产物helpers/helpers.cjs。
另外,package.json中的jsdelivr和unpkg字段均指向./dist/chart.umd.min.js,说明 CDN 场景默认分发的就是这个 UMD 构建。sideEffects字段则显式声明了./auto/auto.js、./auto/auto.cjs、./dist/chart.umd.min.js、./dist/chart.umd.js四个“有副作用”的文件——因为自动注册和 UMD 全局挂载本身就依赖模块执行时的副作用,这一点直接影响打包器能否安全地摇掉它们。
构建侧的对应关系可以在 rollup.config.js 中确认:UMD 产物dist/chart.umd.min.js由入口 src/index.umd.ts 生成,ESM 产物dist/chart.js由 src/index.ts 生成。两种入口的差异正是后文“自动注册 vs 手动注册”的分水岭。
若使用 React、Angular、Vue 等前端框架,官方建议查阅社区整理的第三方集成封装(awesome-chartjs 列表),本文聚焦官方包本身的集成。
Script Tag:最直接的 UMD 集成
不依赖任何打包工具时,直接用<script>引入 UMD 构建并调用全局Chart即可:
<script src="path/to/chartjs/dist/chart.umd.min.js"></script> <script> const myChart = new Chart(ctx, {...}); </script>这个用法能成立的原因在 UMD 入口源码中写得非常明确。src/index.umd.ts 在执行模块时做了三件事:
- 一次性注册全部内置组件:
Chart.register(controllers, scales, elements, plugins);(src/index.umd.ts#L28); - 把
helpers、Animation、Animations、Element、Scale等 API 挂载到Chart命名空间,并通过Object.assign(Chart, controllers, scales, elements, plugins, platforms)保持与 ESM 扩展的兼容; - 在浏览器环境下执行
window.Chart = Chart,从而支持<script>场景下的全局访问。
因此 UMD 构建是“开箱即用”的完整包:所有控制器、元素、刻度和插件都已完成注册,代价是无法做 Tree-Shaking,产物包含全部功能。
Bundler 集成:Webpack、Rollup 等打包器
Chart.js 支持 Tree-Shaking,使用打包器时需要自行导入并注册用到的控制器、元素、刻度和插件。根据对包体大小的敏感度,分为两条路线。
快速上手:chart.js/auto 自动注册包
如果不在意包体积,直接引入auto包即可获得完整功能:
import Chart from 'chart.js/auto';chart.js/auto并不是另一份实现,而是对主产物的一个“副作用薄封装”。查看 auto/auto.js 全部源码仅 5 行:
import {Chart, registerables} from '../dist/chart.js'; Chart.register(...registerables); export * from '../dist/chart.js'; export default Chart;它的原理是展开注册 src/index.ts#L20-L24 导出的registerables数组:
export const registerables = [ controllers, elements, plugins, scales, ];即把四大类内置组件全部注册进全局注册表,然后把主包的所有导出原样转出、并以Chart作为默认导出。这也解释了为什么auto包必须被声明为sideEffects——注册动作发生在模块顶层执行时,若打包器把它当作纯模块优化掉,图表将全部报“未注册”错误。
注册表的实现位于 src/core/core.registry.js。Registry内部为 controllers、elements、plugins、scales 各建一个TypedRegistry(src/core/core.registry.js#L11-L20),register/unregister会按类型自动路由到对应子注册表,并支持整包(如import * as plugins)批量注册。若创建图表时请求了未注册的组件,_get会直接抛出'"xxx" is not a registered xxx.'错误(src/core/core.registry.js#L175-L181)——这就是手动注册方式漏配组件时的典型报错来源。
包体优化:手动注册组件
优化包体时,只导入并注册应用实际用到的组件即可。插件可以按需裁剪(例如不用提示框就不注册Tooltip),但每种图表都有最低组件要求(通常是该类型的控制器、控制器使用的元素和刻度):
| 图表类型 | 控制器 | 元素 | 默认刻度 |
|---|---|---|---|
| Bar 柱状图 | BarController | BarElement | CategoryScale(x)、LinearScale(y) |
| Bubble 气泡图 | BubbleController | PointElement | LinearScale(x/y) |
| Doughnut 环形图 | DoughnutController | ArcElement | 不使用刻度 |
| Line 折线图 | LineController | LineElement、PointElement | CategoryScale(x)、LinearScale(y) |
| Pie 饼图 | PieController | ArcElement | 不使用刻度 |
| PolarArea 极区域图 | PolarAreaController | ArcElement | RadialLinearScale(r) |
| Radar 雷达图 | RadarController | LineElement、PointElement | RadialLinearScale(r) |
| Scatter 散点图 | ScatterController | PointElement | LinearScale(x/y) |
可用的内置插件(各插件的详细配置见对应文档):
- Decimation:大数据量抽稀
Filler:填充LineElement描述的区域,见面积图- Legend:图例
- SubTitle:副标题
- Title:标题
- Tooltip:提示框
可用的刻度:
- 笛卡尔刻度(x/y):CategoryScale、LinearScale、LogarithmicScale、TimeScale、TimeSeriesScale
- 径向刻度(r):RadialLinearScale
这些组件在源码中的对应位置:控制器在 src/controllers/ 目录(如 controller.line.js)、元素在 src/elements/、刻度在 src/scales/、插件在 src/plugins/。由于src/index.ts按分类导出所有模块(export * from './controllers/index.js'等),手动注册时的典型写法就是按分类挑选导入后调用Chart.register(...),这与注册表_each方法支持的“按类型自动路由 + 整包循环注册”逻辑(src/core/core.registry.js#L124-L146)完全吻合。
Helper 工具函数的独立使用
如果想使用辅助函数(helpers),需要单独从chart.js/helpers包导入并以独立函数方式调用,例如实现“把鼠标事件坐标转换为数据值”(官方交互文档中的 Converting Events to Data Values 示例在打包器环境下的版本):
import Chart from 'chart.js/auto'; import { getRelativePosition } from 'chart.js/helpers'; const chart = new Chart(ctx, { type: 'line', data: data, options: { onClick: (e) => { const canvasPosition = getRelativePosition(e, chart); // 替换为对应的 scale ID const dataX = chart.scales.x.getValueForPixel(canvasPosition.x); const dataY = chart.scales.y.getValueForPixel(canvasPosition.y); } } });从源码结构看,helpers入口 src/helpers/index.ts 聚合了颜色、画布、DOM、缓动、插值、数学等十余个工具模块;getRelativePosition定义于 src/helpers/helpers.dom.ts,负责把鼠标事件换算为相对于 canvas 的坐标。该函数同样是 Chart.js 内部交互逻辑的基础——src/core/core.interaction.js 中 6 处交互模式实现均调用它获取事件位置,src/platform/platform.dom.js 的浏览器平台事件处理也依赖同一函数。也就是说,你在点击回调里手动做的事,正是库内部处理hover/click交互时的标准流程。
CommonJS:动态 import 是正确姿势
因为 Chart.js 是 ESM 库,在 CommonJS 模块中应使用动态import:
const { Chart } = await import('chart.js');仓库自身的集成测试验证了该路径:test/integration/ 下包含node、node-commonjs、typescript-node、typescript-node-next、react-browser等多个真实集成工程,覆盖 Node ESM、Node CommonJS、TypeScript 与浏览器 React 等典型消费场景。需要注意,chart.js的exports["."].require字段指向dist/chart.cjs(package.json),同步require('chart.js')在支持exports的环境中拿到的是 CJS 构建;而官方文档推荐的写法仍是顶层await import,以与 ESM 主入口保持一致的注册行为。
RequireJS:只能加载 UMD 构建
重要:RequireJS 只能加载 AMD 模块,因此务必 require UMD 构建(如dist/chart.umd.min.js),而不能直接加载 ESM 产物:
require(['path/to/chartjs/dist/chart.umd.min.js'], function(Chart){ const myChart = new Chart(ctx, {...}); });使用 TimeScale 时,必须确保日期适配器(如chartjs-adapter-moment)及其对应的日期库在 require Chart.js之后完全加载。可以利用嵌套 require 保证加载顺序:
require(['chartjs'], function(Chart) { require(['moment'], function() { require(['chartjs-adapter-moment'], function() { new Chart(ctx, {...}); }); }); });这一顺序要求源于 Chart.js 的适配器机制:TimeScale 通过Chart._adapters(在 UMD 入口挂载,见 src/index.umd.ts#L31)在运行期查询已加载的适配器,若适配器晚于图表创建才注册,时间刻度将无法解析。
选型建议与验证入口
综合上述四种方式,可以按环境选型:
- 静态页面/CDN:Script Tag 引入
dist/chart.umd.min.js(安装文档说明该文件即 jsDelivr、CDNJS 分发的默认构建); - 现代打包器、追求简单:
import Chart from 'chart.js/auto'; - 现代打包器、追求包体:手动导入所需控制器/元素/刻度/插件并
Chart.register,缺失组件会以"xxx" is not a registered xxx.报错,报错信息可直接定位漏注册的组件; - Node CommonJS:顶层
await import('chart.js'); - RequireJS:加载 UMD 构建,注意日期适配器的嵌套加载顺序。
想进一步验证集成行为时,可参考 test/integration/ 中的各集成工程,以及 test/specs/ 下core.registry.tests.js等针对注册机制的单元测试;组件注册与图表初始化的整体流程可结合 docs/developers/init_flowchart.png 理解。
【免费下载链接】Chart.jsSimple HTML5 Charts using the项目地址: https://gitcode.com/gh_mirrors/ch/Chart.js
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考