Screen_Shot_2014-05-30_at_1.37.33_PM"></div><h1 style=智能工程博客

简介:glitt,一个针对GlimmerX和Ember的类型模板解决方案

发布的詹姆斯·c·戴维斯

找到我:

2021年3月24日下午12:45:34

闪闪发光"width=闪闪发光

TL,博士?

  1. 安装闪烁VSCode扩展或者看到维姆/新维姆下面的部分。
  2. 添加@闪烁/核心@glint / environment-ember-loose到您的余烬应用程序或插件。
  3. 创建一个。glintrc.yml文件在你的应用或插件的根目录中包含:
    环境:ember-loose
  4. (目前)从…进口@glint / environment-ember-loose / glimmer-component在的地方@微光/组件
  5. 享受挤压模板中的红色曲线吧!
    (但是,请记住,Glint仍然是实验性的,因此没有担保等)

婆罗门参,我们非常重视开发人员的经验以及生产高质量的软件。出于这些原因,我们选择在我们选择的前端框架Ember.js中使用TypeScript。TypeScript帮助我们减少了bug,更快地发布了新特性,并增强了开发者的信心。然而,我们的内部开发人员调查显示,在使用Ember时,一个主要的抱怨是缺少组件和路由模板的类型检查。在更广泛的Ember社区中,许多TypeScript用户也提出了这个问题。这是一个棘手的问题,因为TypeScript不知道如何处理。hbs文件。幸运的是,至少存在一个解决方案,这是伟大的不稳定烬语言服务器(UELS)插件els-addon-typed-templates由Alex Kanunikov创建(@生活艺术).这个插件为支持语言服务器协议(LSP)的编辑器带来了Ember模板类型检查,是目前完成这项工作的最佳工具。我们强烈建议您今天使用它进行模板类型检查。

Salsifarians丹•弗里曼詹姆斯•戴维斯随着克里斯KrychoLinkedIn的成员组成了Typed Ember团队,这个团队多年来一直维护着Ember世界中的所有TypeScript内容,包括ember-cli-typescript确定类型定义,并通过安贝社会不和谐和其他渠道。在2019年的EmberConf上,詹姆斯给出了一个说话在Ember上使用TypeScript时,他指出了一个“肮脏的小秘密”,即没有跨模板的类型检查。而Ember TypeScript在服务、实用程序和Ember数据模型等方面已经变得相当不错了组件,模板是将组件(以及我们的应用)绑定在一起的粘合剂。由于缺乏跨越这些边界检查类型的能力,因此留下了一个巨大的情节漏洞。我们最终得到了许多组件类,它们在内部和直接调用TypeScript中编写的其他东西时都是类型安全的,但对在模板中调用的任何东西(包括helper、修饰符和其他组件)没有任何保证。实际上,甚至没有检查组件模板中自己的属性。当静态类型检查操作一个大的连续单元而不是单个单元时,它将变得更加有效。

为了弥补这一点,类型化灰烬团队想出了一个我们命名的解决方案闪闪发光.由Dan Freeman架构,Glint由几个类型检查Ember和Glimmer模板组成,包括检查整个项目的CLI(对持续集成很有用)和完整的编辑器支持。与UELS一样,编辑器支持是通过语言服务器提供的,因此它最终应该与支持的任何编辑器一起工作语言服务协议(LSP).我们最初的目标是Visual Studio Code,因为这是迄今为止在Ember社区中最流行的编辑器2020年恩伯社区调查).我们还通过《Conquer of Completion》(以下简称CoC)将其与Vim/Neovim合作。此外,与TypeScript本身类似,Glint的模板类型检查器可以通过编程方式访问,并最终集成到Ember的构建过程中,就像现在的Ember -cli- TypeScript工作方式一样。

但Glint不仅仅是检查模板!Glint基于相关模板为.ts文件提供反馈。一个很好的例子就是私有组件属性。如果你将一个只在模板中访问的组件属性标记为private, TypeScript会抱怨它没有在组件类中使用。然而,Glint知道模板中组件属性的使用情况,不会对未使用的属性喋喋不休。为了防止VSCode的内置编辑器支持(通过tsserver)为了避免提供冲突反馈,我们建议使用Glint禁用VSCode对工作区的本机TypeScript支持:

如何禁用TypeScript内置的V S Code支持"width=

正在执行模板类型检查

好吧,你可能会说,这听起来很不错,但是Glint真的把TypeScript的全部功能都带给你的模板了吗?是的,确实如此!让我们来看看你能做的一些事情。

首先,它检查类型。

显示模板中由于大小写错误而导致组件属性类型错误的屏幕截图"width=

那就太丢人了。

但是Glint通过语言服务器提供了编辑器支持,所以它可以做更多的事情!忘记了模板中使用的组件属性的类型?我们已经为您提供了关于悬停的快速信息:

悬停时显示组件属性类型的屏幕截图"width=

嗯,我在这里调用的这个组件有些地方不太对,我能快速跳到定义吗?

显示从模板中调用组件的位置跳转到组件定义的屏幕截图"width=

为什么,是的,是的,我能!

哦,你知道什么会很酷吗?:如果我可以重命名组件的.ts文件中的一个符号,模板就会自动更新(反之亦然)。

动画GIF显示了在模板中重命名属性和在组件类中更新属性名"width=

天啊!它起作用了!

快速发现每个组件被调用的地方(你知道,直接从组件)不是很好吗?

显示组件的所有调用的屏幕截图"width=

得到它!

好吧,这些对于写代码和重命名很有用,但是实际上写作模板代码?快把我的自动补全功能给我!!

显示组件模板中组件参数自动完成的屏幕截图"width=

哦,当然!在那里不过,这里有一个很大的警告。闪烁使用@glimmer /语法来解析模板,它不接受无效的模板语法。这means that, say, if you haven’t closed your component invocation yet, you’re not going to get autocomplete. There are some tricks to get around the brittleness of @glimmer/syntax, but the real fix is to make @glimmer/syntax more fault-tolerant, which is a goal of the maintainers. In the meantime, we’re looking at ways to improve this experience.

希望这个小小的味道能激发你的食欲,你已经迫不及待地想尝试一下Glink了。让我们看看如何设置它。

开始

只需几个步骤就可以进行模板类型检查。第一个(假设您使用的是Visual Studio Code)是安装闪烁VSCode扩展.这告诉VSCode在哪里找到Glint的语言服务器,如何运行它,以及如何与它通信。不需要配置,只需要安装它就可以了!正如上面所示,记住在你的工作空间中也要禁用VSCode的内置TypeScript支持,这样你就不会得到冲突的反馈。第二步是添加@闪烁/核心包和@glint / environment-ember-loose对于标准余烬或@闪烁/环境闪烁这篇文章将专注于Ember,但是你可以找到细节GlimmerX在闪光自述中。

接下来,告诉闪烁使用什么环境,掉一个格林特克在你的项目根目录下的配置文件只包含:

环境:ember-loose

我们快完成了。今天要使用Glint,您需要做一些可能感觉有点奇怪的事情,并修改组件导入。你需要从其中导入' Component '

@glint / environment-ember-loose / glimmer-component

而不是

@微光/组件

这是因为当前类型签名@glimmer /组件不允许您指定足够的信息完全类型组件(您可以指定组件参数类型,但目前还没有办法提供类型的块组件块收益率或元素的属性和元素修饰符将被应用属性…….好消息是,我们很快将打开一个RFC来更新@glimmer/component的类型签名,以允许指定这些项(可能在需要时更多)。但是,与此同时,@glint/environment-ember-loose/glimmer-component在功能上与@glimmer/component是相同的,只是使用了不同类型的签名(下面有更多介绍)。

现在,一切都应该正常了!打开一个有.ts支持类的.hbs组件模板,你应该进行类型检查!你可能会看到太多了红色的曲线,即使是应该是正确的,但我们将在下面描述如何修复它。

步骤如下:

  1. 安装闪烁VSCode扩展

  2. 添加@闪烁/核心@glint / environment-ember-loose到您的余烬应用程序或插件。

  3. 创建一个格林特克文件在你的应用或插件的根目录中包含:

    环境:ember-loose

  4. (目前)从…进口

    @glint / environment-ember-loose / glimmer-component

    在的地方

    @微光/组件

如果这还不能让你的工作顺利进行,请访问#st-editor-support安贝社会不和谐.如果您认为遇到了错误,请在闪烁回购

维姆/新维姆

对于Vim和Neovim用户,可以使用《征服》(CoC)作为语言服务器客户端,并将其配置为对.hbs和.ts文件使用Glint。我们建议在本地工作区配置中执行此操作,以便CoC不会尝试对非Glint项目使用Glint。

在应用程序的根目录中启动Vim/Neovim并运行:CocLocalConfig

如果你的项目还没有一个本地的CoC配置,你会被要求确认你想要创建一个.vim目录(你做的)。

它将打开或创建一个.vim / coc-settings.json文件。添加此配置:

tsserver.enablelanguageserver: {闪闪发光: {命令${workspaceFolder}/node\u modules/.bin/glint语言服务器文件类型:【html.handlebar打印稿}}}

这将禁用CoC -tssever(如果安装了),并配置CoC为.hbs和.ts文件使用Glint。

在某些情况下,我们(或社区中的某些人)可能会考虑为Glint创建一个CoC扩展,但就目前而言,上面的工作很好。

其他编辑器

因为Glint编辑器支持是通过语言服务器实现的,所以应该可以使它与任何具有LSP客户端的编辑器一起工作2020年恩伯社区调查, JetBrains ide是第二流行的编辑器(比Vim/Neovim稍微多一点)。typing Ember团队中没有一个是JetBrains用户,我们还没有尝试过让Glint与任何JetBrains IDE一起运行,但是请JetBrains用户(以及其他支持LSP的编辑器的用户)来尝试一下!

CLI闪耀

我们可以在编辑器中完成所有这些激动人心的事情,让我们不要忘记CLI!Glint CLI可能是最有用的附加CI检查,以确保不进行类型检查的模板不会被合并。但是,与tsc一样,它也是一种检查整个项目或在重构时观察整个应用程序是否中断的好方法。

显示指示模板中类型错误的闪烁CLI输出的屏幕截图"width=

要在进行更改时键入检查我们的整个应用程序,您可以传递--watch标志,类似于tsc,Glint将在您将更改文件保存到磁盘时拾取任何更改文件,并让您知道它们是否破坏了类型。

有效利用闪烁

现在我们在模板中检查类型,我们需要添加一些样板文件到模板可调用对象中,以便有效地使用Glint并进行适当的类型检查。

线组件

正如我们前面提到的,我们需要提供更多关于组件的类型信息。Glint期望组件类型签名包含参数类型、yield(如果是块组件)和元素类型属性……应用于。表组件的签名可能如下所示:

出口接口SuperTableSignature<T>//我们有一个'  '作为根元素元素HTMLTableElement//接受一个数组,每行一个arg游戏项目数组<T>//我们接受两个命名块:可选的' header '和必选的//`row`,它将与每个项及其索引一起调用。产量吗?项目T指数数量

然后像这样应用到组件类:

出口默认的超级表<T>扩展组件<SuperTableSignature<T>>

目前只有使用特殊的闪烁版本的@glimmer/component才能正确输入:

进口组件从…起“@glint / environment-ember-loose / glimmer-component”

总的来说,这看起来像:

进口组件从…起“@glint / environment-ember-loose / glimmer-component”出口接口SuperTableSignature<T>//我们有一个' 
'作为根元素元素HTMLTableElement//接受一个数组,每行一个arg游戏项目数组<T>//我们接受两个命名块:可选的' header '和必选的//`row`,它将与每个项及其索引一起调用。产量吗?项目T指数数量出口默认的超级表<T>扩展组件<SuperTableSignature<T>>

此组件的模板可能如下所示:

{{!app/components/super-table.hbs}<表格…属性>{{#如果has-block}}<泰德> <tr>{{收益率}}tr> 泰德>{{/如果}}<tbody>{{#各@items作为|项目指数|}}<tr>{{收益率项目指数}}tr>{{/每个}}tbody> 表格>

您会注意到上面的组件示例实际上应该是一个只包含模板的组件,因为组件类实际上不做任何事情。Glint还不完全支持模板组件,所以现在需要定义一个空的组件类。

余烬成分

如果你的应用程序不是完全的辛烷,你也可以为Ember组件提供类型信息。Ember组件也需要自定义导入。因为他们没有这个。arg游戏,they also need to use a specialArgsFor导入更多的样板文件:

/ / app /组件/ greeting.ts进口组件
ArgsFor
从…起“@glint / environment-ember-loose / ember-component”进口计算从…起“@ember /对象”出口接口GreetingSignaturearg游戏消息一串目标吗?一串产量默认的问候一串//这一行声明我们的组件的参数将被' splsplted '
//实例:
出口默认的接口问候扩展ArgsFor<GreetingSignature>出口默认的问候扩展组件<GreetingSignature>计算“目标”私人得到greetingTarget//因此使' this。目标`a legal `string | undefined`
/ /属性访问:
返回目标??“世界”
{{!app/components/greeting.hbs}{{收益率concat消息this.greetingTarget}}

模板注册表

如今,Ember在运行时动态解析模板中调用的内容(尽管这将最终改变).由于这种动态特性,我们必须帮助Glint(和TypeScript)做一些改进。我们需要一种方法来告诉lint我们在模板中调用的这些东西实际上是在哪里定义的。我们通过“类型注册表”来做到这一点。如果您使用过Ember Data和TypeScript,那么您可能熟悉在每个模型的底部添加模型到类型注册表model.ts文件。闪烁模板类型注册表的工作原理完全相同。例如:

/ / app /组件/ greeting.ts进口组件从…起“@glint / environment-ember-loose / glimmer-component”出口默认的问候扩展组件声明模块“@glint / environment-ember-loose /注册表”出口默认的接口登记处问候typeof问候

只需添加这一点,就可以告诉闪烁如何找到您的组件。我们正在寻找可能自动生成这个注册表的方法,或者可能提供一个代码演示程序,将它自动添加到你所有的TypeScript可调用对象中。UELS -addon-typed-templates插件使用自动发现方法。我们担心这种方法在大型应用程序中的性能影响,并且,由于模板严格模式即将到来,我们现在选择只支持类型注册中心方法。

助手

到目前为止,我们只关注组件,但helper是另一种类型的可调用对象,我们可以键入检入模板。函数helper只需要使用临时自定义的Glint导入并添加到注册表中:

进口助手从…起“@glint / environment-ember-loose / ember-component /助手”函数重复参数个数一串数量返回参数个数0重复参数个数1常数repeatHelper助手重复出口默认的repeatHelper声明模块“@glint / environment-ember-loose /注册表”出口默认的接口登记处“重复”typeofrepeatHelper
{{!应用程序/组件/一些组件。哈佛商学院}}{{重复你好3.}}

基于类的helper需要自定义导入,但也需要提供类似组件的类型签名:

进口帮手从…起“@glint / environment-ember-loose / ember-component /助手”出口接口附签纳米达斯前缀吗?一串后缀吗?一串位置参数一串返回一串阿菲克斯助手扩展帮手<附签>// TypeScript要求你为被覆盖的方法提供类型。这//表示必须提供与签名匹配的方法类型。//最好的方法是直接引用它们,如下所示。计算参数个数附签“PositionalArgs”前缀后缀附签“NamedArgs”附签“返回”返回$ {前缀$ {参数个数0$ {后缀出口默认的阿菲克斯助手声明模块“@glint / environment-ember-loose /注册表”出口默认的接口登记处“词缀”typeof阿菲克斯助手
{{!应用程序/组件/一些组件。哈佛商学院}}{{词缀友善的前缀联合国}}{{词缀友善的后缀洛克}}{{词缀信任前缀后缀艾德}}

修饰符

现在我们有了第三种可以在模板中调用的东西,那就是修饰符。与函数式helper一样,函数式修饰符只需要自定义的Glint导入和添加到注册表中。考虑一下这个{{在}}克隆:

/ /应用程序/修饰符/ when.ts进口修饰符从…起“@glint / environment-ember-loose / ember-modifier”常数whenModifier修饰符元素HTMLElementeventName处理程序一串=>未知的=>元素addEventListenereventName处理程序返回=>元素removeEventListenereventName处理程序出口默认的whenModifier声明模块“@glint / environment-ember-loose /注册表”出口默认的接口登记处什么时候typeofwhenModifier
{{!应用程序/组件/一些组件。哈佛商学院}}<按钮类型按钮{{什么时候点击这个.onClick}}>点击我!按钮>

基于类的修饰符需要额外的类型签名样板,如组件:

/ /应用程序/修饰符/ say.ts进口修饰符从…起“@glint / environment-ember-loose / ember-modifier”出口接口SayModifierSignature纳米达斯乘数吗?数量位置参数输入一串元素HTMLDivElementSayModifier扩展修饰符<SayModifierSignature>didReceiveArguments无效元素innerTextarg游戏位置0重复arg游戏命名乘数??1毁灭无效元素innerText''出口默认的SayModifier声明模块“@glint / environment-ember-loose /注册表”出口默认的接口登记处typeofSayModifier
{{!应用程序/组件/一些组件。哈佛商学院}}<div{{你好乘数2}}> div>

引擎盖下的秘密

那么闪闪到底是怎么做到的呢?TypeScript不理解模板语法,所以我们必须把模板转换成TypeScript的东西理解。Glint使用一个转换,将模板语法转换为TypeScript,并将其注入组件类。这一切都发生在闪烁内部的内存中,因此您永远不会在文件中实际看到转换后的模板。扩展后的组件类通过编程方式提供给TypeScript编译器TypeScript语言服务API,设计用于按需处理和快速反馈。Glint接收来自TypeScript编译器的反馈,并将增强组件类中的位置映射回模板中的原始位置。它之所以能够做到这一点,是因为它在转换模板时跟踪位置。在编辑器中使用时,映射的反馈随后提供给Glint语言服务器,该服务器将其发送到编辑器的LSP客户端进行显示。Glint CLI的工作原理类似,使用相同的转换模块,但使用打印稿编译器API处理所有文件并提供适合终端显示的输出。

Glint由几个软件包组成:

加上两个环境包:

以及为闪烁语言服务器的Visual Studio Code扩展:

我们正在计划后续深入到闪烁内部,所以期待更多的细节即将到来!

JavaScript支持

所以,Glint适用于使用TypeScript的项目,但如果你不是呢?好吧,我们正在努力!闪烁是动力通过,但是TypeScript有能力从JavaScript文件提取类型信息@ts-check还有JSDoc,我们很幸运艾琳的歌手LinkedIn加入我们,致力于支持闪烁JavaScript。这方面的工作才刚刚开始,请继续关注!

下一步是什么

闪烁,就像今天存在的一样,仍然是非常实验性的。我们强烈建议您尝试一下,但目前不建议将其用于生产应用程序和插件。同样,Alex Kanunikov的不稳定的余烬语言服务器(UELS)插件els-addon-typed-templates是现在去灰烬模板类型检查。作为的一部分官方打印稿的支持谈到Ember,我们计划更新Glimmer组件类型签名,以支持类型化模板所需的所有类型信息(可能是我们上面描述的签名)。一旦实现了这一点,您就不需要使用定制的Glint导入,而将Glint用于生产项目将变得更加合理。我们也希望与亚历克斯·卡努尼科夫合作(@生活艺术)将Glint集成到Ember语言服务器中。现在,请尝试Glint模板类型检查,并让我们知道您的想法!新的#st编辑器支持频道安贝社会不和谐是讨论闪烁的好地方。希望在那里见到你!

主题:GlimmerXEmber.js线打印稿typed-templates模板类型检查typechecking

评论的Disqus

最近的职位

    Baidu