ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

typescript-book 实战:TypeScript 动态 import 表达式与 webpack 代码分割集成指南

typescript-book 实战:TypeScript 动态 import 表达式与 webpack 代码分割集成指南 教程【免费下载链接】typescript-book:books: The definitive guide to TypeScript and possibly the best TypeScript book :book:. Free and Open Source 项目地址https://gitcode.com/gh_mirrors/ty/typescript-book点击查看免费下载动态 import 表达式Dynamic import expressions是 ECMAScript 的新特性允许在程序运行到任意位置时异步请求一个模块它与 webpack 的 Code Splitting代码分割配合可以让应用先加载一个最小的 bootstrap 包、按需异步加载其余功能。本文以本仓库typescript-book的 dynamic-import-expressions 示例 为骨架完整讲解 TypeScript 2.4 中import()的写法、tsconfig.json的关键配置尤其module: esnext以及如何验证编译产物确实把import()原样保留给 webpack 做代码分割。读完本文你将掌握懒加载 代码分割这一现代前端优化的标准姿势并理解它为什么依赖编译配置而非自动产生。什么是动态 import 表达式动态 import 表达式是 ECMAScript 的新特性它允许用户在程序的任意时间点异步请求一个模块——而不是像静态import那样只能在模块顶层声明、且必须在模块加载时同步解析。静态形式import moment from moment;—— 在模块顶层声明依赖加载时机固定。动态形式import(moment)—— 在函数体、事件回调、条件分支等任意位置调用返回一个Promise模块在请求时才被解析和加载。这一特性由TC39JavaScript 委员会提出其官方提案名为import() proposal for JavaScript当时处于 stage 3 阶段。在 TypeScript 2.4 中这一特性被正式支持详见 TypeScript 官方的Whats new in TypeScript说明。本仓库将这一主题收录在 Project项目组织 章节下与 Modules、Namespaces 等模块化话题并列可见它属于如何组织 TypeScript 项目这一层面的关键能力。import() 的运行时语义从使用方式看import()与fetch、Promise类似是异步的import(moment) .then((moment) { // 模块加载完成后在这里使用 }) .catch((err) { // 加载失败时的处理 });由于它返回Promise加载失败会走catch分支这让你可以优雅地处理网络错误或资源缺失的情况例如降级提示、重试逻辑等。为什么需要代码分割先加载最小的 bootstrap单个巨型 bundle 的问题是用户访问首页时浏览器必须下载、解析并执行整个应用的代码哪怕其中 90% 的功能他根本不会立刻用到。随着应用增长首屏时间会越来越长。webpack等打包工具提供了一项名为Code Splitting代码分割的能力把 bundle 拆分成多个 chunk这些 chunk 可以在稍后的某个时间点被异步下载。典型收益包括先服务一个最小的 bootstrap bundle让首屏尽快可交互把重量级依赖如日期库、图表库、地图库单独成 chunk只在真正用到时才下载按路由拆包用户进入某个页面时才加载该页面的代码。动态 import 表达式正是实现代码分割的语法基础——打包器看到import()调用就知道这里应当切出一个异步 chunk。常见误区TypeScript 不会自动帮你做代码分割一个非常自然的想法是既然我用了 TypeScript 2.4 的动态 import 表达式而开发流程里又用了 webpack那么编译后是不是就自动产生bundle chunk、自动对最终 JS 做代码分割了并非如此事情没那么简单。原因在于这取决于我们所使用的 tsconfig.json 配置。关键点在于webpack 的代码分割支持两种类似的技术来实现目标技术状态说明import()推荐preferred基于 ECMAScript 提案标准语法require.ensure()旧方案legacywebpack 特有的历史 API而这意味着期望的 TypeScript 编译输出是把 import() 语句原样保留而不是把它转译成其他任何东西。只有import()被原样保留在产物中webpack 才能识别它并执行代码分割如果 TypeScript 把它转译成了require(...)或Promise.resolve().then(() require(...))webpack 就无从切分 chunk 了。实战懒加载 moment 并实现代码分割下面进入本仓库提供的完整示例。目标需求很明确懒加载 moment 库同时实现代码分割——即让 moment 库位于一个独立的 JS chunk 中只在需要时才被加载。源代码dynamicImportExpression.ts完整的可运行源码位于 code/dynamic-import-expressions/dynamicImportExpression.tsfunction myApp() { import(/* webpackChunkName: momentjs */ moment) .then((moment) { // lazyModule has all of the proper types, autocomplete works, // type checking works, code references work \o/ const time moment().format(); console.log(TypeScript 2.4.0 Dynamic Import Expression:); console.log(time); }) .catch((err) { console.log(Failed to load moment, err); }); }逐点拆解这段代码import(...)出现在函数体内这正是在程序中任意点异步请求模块的体现静态import无法写在函数体里。/* webpackChunkName: momentjs */魔法注释这是 webpack 支持的注释指令用来给生成的 chunk 命名。编译时该注释会被原样保留webpack 解析后即可生成名为momentjs的独立 chunk 文件。.then((moment) ...)回调参数moment拥有完整的类型信息——注释中特别强调autocomplete自动补全可用、type checking类型检查可用、code references代码引用跳转可用。这是 TypeScript 相对纯 JS 的显著优势动态导入的模块依然享受静态类型推断而不是退化为any。.catch((err) ...)处理模块加载失败的情况。tsconfig.json 配置详解示例配套的tsconfig.json位于 code/dynamic-import-expressions/tsconfig.json{ compilerOptions: { target: es5, module: esnext, lib: [ dom, es5, scripthost, es2015.promise ], strict: true, moduleResolution: node }, files: [ ./dynamicImportExpression.ts ] }其中与动态 import 直接相关的选项module: esnext—— 本文的核心关键配置。module选项控制生成什么模块格式的 JavaScript。当取值为esnext在 TS 2.4 时代对应 webpack 需要的语义时TypeScript不会把import()转译为require或System.import等任何形式而是原样保留 import() 语句作为 webpack Code Splitting 的输入。若module取commonjs等传统格式import()就会被转译掉代码分割也就无从谈起。target: es5编译目标为 ES5保证产物能在旧浏览器运行import()本身不依赖 ES 模块运行时交给 webpack 处理后即可工作。lib: [dom, es5, scripthost, es2015.promise]显式声明需要的库文件。加入es2015.promise是因为.then/.catch链依赖Promise类型需要引入 ES2015 的 Promise 声明才能通过类型检查。strict: true开启全部严格类型检查选项保证示例代码在严格的类型环境下依然能通过编译。moduleResolution: node使用 Node 风格的模块解析策略这是 webpack 项目解析node_modules中的moment的常见配置。关于module与moduleResolution等选项的完整说明可参考 docs/project/tsconfig.md。值得注意的是本仓库还保留了一份更完整的配置见 docs/project/dynamic-import-expressions.md包含jsx: react、declaration、sourceMap、outDir、typeRoots、types等选项用于真实的 React 类型声明场景{ compilerOptions: { target: es5, module: esnext, lib: [ dom, es5, scripthost, es2015.promise ], jsx: react, declaration: false, sourceMap: true, outDir: ./dist/js, strict: true, moduleResolution: node, typeRoots: [ ./node_modules/types ], types: [ node, react, react-dom ] } }其中typeRoots与types用于精确控制从node_modules/types引入哪些类型声明outDir控制编译产物输出目录sourceMap生成调试用的 source map——这些都是真实 webpack 工程里的常见配置。编译产物验证import() 被原样保留验证配置是否生效最直接的办法是查看 TypeScript 的实际编译输出。仓库中的编译产物 code/dynamic-import-expressions/dynamicImportExpression.js 展示了结果use strict; function myApp() { import(/* webpackChunkName: momentjs */ moment) .then(function (moment) { // lazyModule has all of the proper types, autocomplete works, // type checking works, code references work \o/ var time moment().format(); console.log(TypeScript 2.4.0 Dynamic Import Expression:); console.log(time); }) .catch(function (err) { console.log(Failed to load moment, err); }); }对比源码可以清晰看到import(/* webpackChunkName: momentjs */ moment)被原样保留包括魔法注释webpackChunkName: momentjs也完整保留——这正是 webpack Code Splitting 需要的输入形式箭头函数被降级为function、const降级为var因为target: es5文件顶部出现use strict——从源码结构看这是严格模式相关编译选项strict开启后的典型产物特征.then/.catch链原样保留等待 webpack 在构建期替换为实际的 chunk 加载逻辑。这个编译产物从源码级证实了本文的核心论断TypeScript 的工作是把import()原样交给打包器切分 chunk 的工作由 webpack 完成。依赖与版本环境示例工程还包含 package.json记录了运行前提typescript: ^2.4.1动态 import 表达式从 TypeScript 2.4 开始支持因此编译器版本不得低于 2.4moment: ^2.18.1示例中被懒加载的目标库工程作者为 Jose Quinto Zamora。复现实验的前提是安装上述依赖后运行tscTypeScript 编译器会在当前目录及上级目录查找tsconfig.json也可用tsc -p ./path-to-project-directory指定项目目录详见 docs/project/tsconfig.md再将编译产物交给 webpack 构建观察是否生成独立的momentjschunk。重要注意事项总结结合原文档与仓库源码使用动态 import 表达式做代码分割时有几个关键点必须牢记module: esnext是让 TypeScript 产生供 webpack Code Splitting 使用的 mimic import() 语句的关键。若省略或改用其他模块格式import()会被转译代码分割失效。TypeScript 只负责保留语法不负责切分 chunk。期望的产物是import()语句原样保留chunk 的切分、命名、异步下载完全由 webpack 在构建期完成。务必使用import()而非require.ensure()。后者是 webpack 特有的 legacy API前者是基于 ECMAScript 提案的标准语法是官方推荐方式。类型体验完整保留。动态导入的模块在.then回调中依然具备完整的类型推导、自动补全与引用跳转能力不必牺牲类型安全来换取性能优化。进一步探索本仓库围绕该主题提供的完整素材如下便于你对照阅读与复现主文档docs/project/dynamic-import-expressions.md源码与产物code/dynamic-import-expressions/dynamicImportExpression.ts、code/dynamic-import-expressions/dynamicImportExpression.js工程配置code/dynamic-import-expressions/tsconfig.json、code/dynamic-import-expressions/package.json关联主题模块化基础见 docs/project/modules.md编译上下文与 tsconfig 全局概念见 docs/project/compilation-context.md 与 docs/project/tsconfig.md从项目组织层面理解这套机制后你便能在实际工程中放心地用import()按需加载路由、组件与重型依赖在保持 TypeScript 类型安全的同时获得 webpack 代码分割带来的首屏性能收益。赞分享教程【免费下载链接】typescript-book:books: The definitive guide to TypeScript and possibly the best TypeScript book :book:. Free and Open Source 项目地址https://gitcode.com/gh_mirrors/ty/typescript-book点击查看免费下载相关推荐Repomix 社群生態系全覽從 VSCode 擴充、桌面應用到語言實作與 AI 整合工具Repomix 社群生態系全覽從 VSCode 擴充、桌面應用到語言實作與 AI 整合工具 导读 本文聚焦 Repomix 開源專案將整個程式庫打包成單一开发工具MCP 服务AI 应用webpack 代码分割实战基于 ES Module import() 的按需加载与动态 import 异步上下文全面解析webpack 代码分割实战基于 ES Module import 的按需加载与动态 import 异步上下文全面解析 ES Modules 的标准 impo前端构建开发工具提升设计效率300%Size Marks让UI尺寸标注不再繁琐提升设计效率300%Size Marks让UI尺寸标注不再繁琐 Size Marks是一款专为Web设计师和前端工程师打造的Photoshop脚本工具能将矩开发工具上一篇如何永久保存你的微信聊天记录WeChatMsg完整指南让数据真正属于你下一篇Hono.js 静态文件服务与SPA路由的实现技巧创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表