Less.js: ES6 和汇总

创建于 2015-09-14  ·  62评论  ·  资料来源: less/less.js

我愿意(如果我有时间的话)

  • [x] 将库移动到 es6/
  • [x] 将 es6/ 转换为 es5/ 文件夹
  • [x] 使用rollup构建浏览器单个文件

这将是一个新的主要版本,我还将删除浏览器捆绑的承诺,正如我在其他问题中提到的那样。

在我做之前有什么反对意见吗? 除了需要(用于汇总)之外,我不会开始将所有内容都转换为 es6,但如果他们愿意,其他人可以自由地使用 less.js“升级”作为学习 es6 的一种方式。


_由@matthew-dean 更新——我最终将lib/保存在同一个文件夹中以保留(一些?)git历史记录,而不是同时编译(向上编译?)和移动。 这些模块不会编译为es5/或等效的。 相反,有一个适用于 Node 6+ 的 CommonJS 单文件构建,以及一个浏览器构建。_

feature request high priority

最有用的评论

转换完成并合并! 见: https ://github.com/less/less-meta/issues/32

所有62条评论

不。 一段时间以来,我一直在思考同样的问题。 使用 TypeScript 怎么样? 代码提示/真实对象链接可能会使开发/贡献更容易。 虽然我不知道这是否会给知识带来负担/障碍。

我也在考虑同样的思路,我们应该考虑使用 es6 集合来解析 / AST,然后为 es5 构建使用 polyfill,例如https://github.com/Benvie/harmony-collections。 在 es6 环境(现在是 Node.js 和最新的浏览器)中,理论上应该加快解析/评估速度,因为内存开销减少和 AST 构建速度更快。

使用 TypeScript 怎么样? 代码提示/真实对象链接可能会使开发/贡献更容易。 虽然我不知道这是否会给知识带来负担/障碍。

我们可以考虑在 ES6 之后 - es6 不排除 typescript,因为 typescript 也是一个 es6 转译器.. 这将是这之后的一个额外步骤。

我个人不会推荐打字稿,除非有大量的额外工作或更少的重构。 国际海事组织打字稿

  • + 使了解 typescript 的新人的开发更容易
  • + 提高可维护性

    • 要求人们知道或学习最少的打字稿


    • 编写代码需要更长的时间才能输入

我也在考虑同样的思路,我们应该考虑使用 es6 集合来解析 / AST,然后为 es5 构建使用 polyfill,例如https://github.com/Benvie/harmony-collections。 在 es6 环境(现在是 Node.js 和最新的浏览器)中,理论上应该加快解析/评估速度,因为内存开销减少和 AST 构建速度更快。

我不会使用那个polyfill,这个项目看起来已经死了(也许也是因为和谐这个名字已经死了)。

此外,不幸的是,我不确定 ES6 原生等价物是否更快 - https://jsperf.com/property-access-object-array-map-weakmap/6。 可悲的是,例如 Promise polyfill 比本机实现更快:(

:+1:

所有的好点。 对 ES6 / Babel 进行标准化通常会使事情不仅更容易编写,而且更容易阅读,尤其是在进行原型继承时。

就那个 jsperf 测试而言,这并不是一个公平的例子。 我希望 Weakmap 对该特定测试的执行速度较慢。 从理论上讲,Less 最好创建一堆不同的对象形状和类型,然后对它们进行评估。 不过不确定。 我找到了一些我想最终测试(并希望添加)的好库,我们可以在其中挂钩单个函数来进行精细的基准测试,而无需将任何“基准测试挂钩”放入库中。 我希望设置一些东西(当我有时间时,谁知道那会是什么时候),以便您可以对 Less.js 中的函数进行一种 jsperf 测试,但是本地开发/分支更改为 Less 与当前版本,并使用几种测试 .less 文件。 正如我之前提到的,对于我们的特定用例,我们不需要猜测哪个更快。 从理论上讲,我们可以在某个功能级别与原始对象之间分入 WeakMap,在该位置运行基准测试,并根据结果做出决定。

@lukeapage写道:
国际海事组织打字稿

  • + 使了解 typescript 的新人的开发更容易
  • + 提高可维护性

    • 要求人们知道或学习最少的打字稿


    • 编写代码需要更长的时间才能输入

还有一个您忽略的未提及的非常重要的好处:
TypeScript 的类型化模式迫使您使用稳定的变量类型,它强制执行稳定的类型形状,从而提高编译器静态_和_动态分析代码的能力,从而生成_更好_优化的代码并停止(或至少显着减少)从优化代码回到慢解释代码。

迁移到 TypeScript 可能比迁移到 ES6 贡献更多,恕我直言。

通过键入模式,您的意思是禁止任何?

我在一个小项目上尝试过,到处都有注释..它结束了
有很多代码,因为转译器不是超级聪明。

至于有多少变量改变了变量类型,我不确定。 所以..
不相信性能优势会很明显。

@rjgotten我没有使用过 TypeScript,但这些都是好点。 如果您使用 TypeScript 的智能感知/自动完成环境,它实际上可能会帮助新的贡献者,因为它会在您进行更改时完成类型/对象形状。 如果设计得当,它可以作为一种自我记录/熟悉/防错工具,供贡献代码更改的人使用。 但关键可能在于 TypeScript 设计。

总的来说,会有性能优势吗? 这更难确定。 这更像是艺术家而不是画布。

尽管我的目标是在我自己的项目中使用 TypeScript,但我可能更倾向于同意@lukeapage ,主要是因为,除非我们这里的任何人都是 TypeScript 专家,否则我不确定我们是否可以有效地使用最初。

此外,迁移到 ES6 并不妨碍将来使用 TypeScript。 Microsoft / Google 的目标是让 TypeScript 2.0 成为 ES6 的超集,所以我们总是可以从 ES6 / Babel 开始,然后添加适当的类型并切换到 TypeScript 转译器。 我的怀疑是 TypeScript 将“赢得”转译语言,只是因为编译时/自动完成的好处比非类型化的 JavaScript 要大得多。 所以......我想这意味着我认为使用 TypeScript 可能是不可避免的,但这并不意味着我们必须立即使用它。

我想在某个时候讨论一种不同的 Less 架构方法,但这更多的是与此相切的讨论。

通过键入模式,您的意思是禁止任何?

不,一般只使用类型变量。 一般来说,您_可以_禁止使用 Any,但它(至少实际上)是一个坏主意,因为它往往会导致大量代码膨胀以满足打字系统的要求。

但是,在函数上使用类型化参数确实意味着调用者(至少用 TypeScript 编写的调用者)_必须_尊重给定的类型。 这意味着类型化函数可用于在适当的情况下保护 Less 编译器内部工作的类型稳定性,并保证特别重要的函数将得到很好的优化。 (不要忘记;JS 引擎通常在函数级别进行优化......)

很酷的工作。 Germaine 在讨论中,我正在查看代码并很快发现:

if (typeof index === 'number') {   

AFAIK 在 TypeScript 中永远不需要这种类型的完整性检查。 如果每次在运行时将索引类型转换为字符串以进行字符串比较以检查值的类型,则类似的事情可能会加起来。 在 TypeScript 中,如果调用了传递索引的函数,但该类型有时不是数字,并且索引仅 _accepted_ 数字,则该函数将在编译时因类型不匹配而失败,而不是需要在运行时进行测试,此时此类检查的成本更高。

另一方面,这可能是一个孤立且罕见的例子; 这只是我遇到的似乎相关的东西。

我认为显式类型的最大优势在于它允许更强大的工具。 查找所有(且唯一)调用函数或覆盖它的位置只是一个键盘快捷键。 找出可用对象的哪些功能是零工作,重构更安全,因为编译器会产生更多错误。 它也使学习新的代码库变得更容易——了解全局,找出代码的哪一部分依赖或遵循代码流而不运行它在 javascript 中比在 java 中更难(例如),因为类型化编辑器更强大。

我还没有使用过 TypeScript,所以我不知道工具是否足够成熟,是否值得。 javascript 的优点是大家都知道,TypeScript 鲜为人知。

总的来说,如果我们计划进行某种更大的重构或巨大的新功能,我认为迁移到 TypeScript 是有意义的,但是当我们只是修复小错误时,它可能会做太多的工作。

如果我们计划进行某种更大的重构或巨大的新功能,我认为迁移到 TypeScript 是有意义的,但是当我们只是修复小错误时,它可能会做太多的工作。

情况可能是这样,实际上,为了务实, @lukeapage已经承担了这项工作,所以我倾向于说他应该在这个时候做出最后的决定。 :-)

嘿,关于这个:我们应该做些什么来让人们知道代码库正在发生变化? 我假设否则你会有合并冲突。

不,不应该有太多的冲突。 第一步只是 es6 模块 - 不是
移动任何文件,然后我们可以透明地添加 babel 或 typescript。

嗨,伙计们,现在怎么样了?

我可以解决这个问题。 @matthew-dean 你会接受拉取请求吗?

@alexlur当然! 我唯一关心的是3.x分支的重构而不是合并冲突。 所以最好从那里分叉/分支。 此外,由于编写了这个问题,现在有一个使用src/dist/的完善约定。 但是, lib/有时用作src/ ,因此可能不需要重命名。

还会对 Gruntfile 进行少量重写,以便测试使用构建而不是lib/ 。 (浏览器测试所做的是在test/而不是dist/中构建。 dist/文件夹是新版本的特殊 Grunt 任务。在测试时,它应该构建到test/ ) 这样做之后,只要测试通过,你应该是好的。

@matthew-dean 你好。 我已经完成了重构,但我不知道如何配置 Gruntfile 以在新构建的文件上运行测试。

也许我能做的是将您的更改合并到一个单独的分支中,然后查看集成测试。 我只是快速查看您的更改。 如果我错了,请纠正我,但at-rule是否错误地是assignment节点? 还是 Github 只是弄乱了它的显示方式?

很好,我使用了错误的文件。

是否有 less.js 必须支持的浏览器/Node.js 的最低版本? Node.js 对Promise (自 0.12 起)有相当好的支持,而在浏览器中使用通常是为已经运行最新浏览器版本的开发人员提供的。

编辑:

Less.js 支持所有现代浏览器(Chrome、Firefox、Safari、IE11+ 和 Edge 的最新版本)

只有 Internet Explorer 11 没有内置Promise

@alexlur
对于 Less 的浏览器内版本,我建议创建一个less.Promise属性,并将其默认设置为window.Promise 。 然后让 Less 通过less.Promise消耗 Promise 类。

这样,现代浏览器的用户以及在加载 Less 之前已全局填充 Promise 的用户,将让一切都神奇地工作。 而那些不想——或者出于某种原因不允许——全局 polyfill 的用户可以通过一个微小的额外步骤来使事情正常进行。 他们只需要在实际使用 Less 之前手动将他们选择的 Promise 实现分配给less.Promise

@rjgotten @alexlur Less.js 已经设置了Promise填充。 不需要在那里做任何额外的工作。 大多数代码都使用这种模式:

https://github.com/less/less.js/blob/55380d49e96a6ed561cac4d13a774830aa3c17a3/lib/less/import-manager.js#L5

在节点方面,这个问题仍然存在: https ://github.com/less/less.js/issues/3121

但是,在没有任何反馈的情况下,并且贡献者数量相当多,我倾向于只说 Node 4+ 是目前要走的路。 我们应该更新文档/测试以反映这一点。

@matthew-dean 它应该准备好合并到一个单独的分支

@alexlur谢谢! 我会尽快看看。 可能会在下周(除非其他人有空去检查)。

此问题已自动标记为过时,因为它最近没有活动。 如果没有进一步的活动,它将被关闭。 感谢你的贡献。

我创建了一个重构为 TypeScript 的 fork。

@glixlur 😮 哇,所有测试都通过了吗? 并在dist/中构建一个相同的 less.js ?

@matthew-dean 我仍在努力,但作为日常驱动程序,我的浏览器构建没有遇到任何问题。 从技术上讲,使用 rollup 可以让我的 fork 在性能上占据优势,但我没有数据来支持它。

@less/core 应该对此进行调查,看看我们是否可以将其自动化以进行一次性转换 - https://github.com/lebab/lebab

@matthew-dean 完成后,我会向您发送拉取请求。

@glixlur哦! 好的,在你之前的 PR中,你说你没有时间做这个。 如果你还在做这个,👍

@matthew-dean 我将限制自己仅转换为 ES6 并稍后离开 TypeScript 部分。

@glixlur我认为 ES6 可能是向前迈出的最“社区友好”的第一步,所以这很完美。 我不确定每个人都使用 TypeScript,但肯定 ES6 流程会很棒。

@matthew-dean 我假设支持的最低平台是 Node 6 和 IE11?

@glixlur Appveyor 当前设置为测试节点 4。这会让事情变得更困难吗? 理想情况下,它将是一个 Babel 将src/文件夹转换为(替换) lib/ (和浏览器的dist/ )文件夹,以便分发给节点/浏览器。 所以我会假设 Babel 正在做大部分的转译到 ES5 的工作。

完成,但需要让测试正常工作。 PhantomJS 已被弃用,并且不支持 ES5 之后的任何内容。

@glixlur不错! 回复:PhantomJS,它确实需要被 Chromy 之类的东西取代。 见: https ://github.com/less/less.js/issues/3240

@glixlur另外,这是 Chromy / headless Chrome 相关的: https ://github.com/less/less.js/issues/3262

@glixlur关于 PhantomJS - 这些测试是针对捆绑的浏览器版本运行的,您可能会将其转换为 ES5,对吗? 为什么 PhantomJS 不能与 ES5 输出包一起工作?

@matthew-dean 是的,但是在运行带有 Babel 转译文件的 PhantomJS 时会使用Symbol的错误。

@glixlur您需要转译输出中的babel-polyfill 。 这是一个很好的指标,它尚未正确转换。 请参阅以下问题: https ://github.com/babel/babel-preset-env/issues/203

@matthew-dean babel-polyfill将 87.3KB 缩小到输出文件。 你可能不想要那个。

@glixlur
您不想要babel-polyfill还有其他原因。 也就是说,它通过在window上发布 polyfill 并修改像Array这样的原生类型的原型来影响全局命名空间。

改为查看babel-runtimebabel-plugin-transform-runtime包。

此外,iirc Babel 团队正在努力限制由transform-runtime捆绑的 polyfill,与babel-env预设限制语言转换相同。 但是他们在这方面的工作还没有完成并且普遍可用。 最终会成为 Babel 7 的东西,无论如何它仍处于测试阶段,所以没有直接用处。 但绝对是未来可取的。

@glixlur @rjgotten啊。 我应该澄清一下,我不确切知道使用哪种解决方案 re: Babel。 只是因为Symbol是未定义的,因为它不是 polyfill(小马填充?),它也将在 IE11 中。 所以也许它不是 polyfill,但我相信通过正确的 Babel 设置,它应该给你一个范围Symbol定义。 所以也许是最小浏览器版本的问题?

使用正确的 Babel 设置,它应该给你一个范围Symbol定义

确实会。
这些设置相当于使用transform-runtime插件及其为Symbol等较新的内置插件注入别名的能力,而不是依赖于babel-polyfill

phantomjs 应该被弃用吗?

考虑到它已经死了?
大概是。

@glixlur见: https ://github.com/less/less.js/issues/3240

转换完成并合并! 见: https ://github.com/less/less-meta/issues/32

Welp,本周我了解到 JavaScript 中的Class不仅仅是函数原型的语法糖,这导致了这个问题: https ://github.com/less/less.js/issues/3414

具有讽刺意味的是,我用另一段与 Less 无关的代码遇到了同样的事情,就像 2 周前一样,我清楚地记得当时的想法:

哎呀,我想知道对于 Less 的 ES6 转换是否会导致此类问题。

好吧:问题回答了,我猜?

@matthew-dean,我_so_ 并不羡慕那些对你的工作表达不满的用户风暴。 我很同情你不得不处理这种情况。 :微笑:
幸运的是,似乎没有人发生世界末日,并且处理得井井有条。

@rjgotten大声笑,我的意思是,你怎么能预料到这样的事情? 最安全的做法是根本不转换,或者从不使用类,但这会使代码库不那么冗长(好吧,或者可能会,有很多进一步清理的机会)。 从技术上讲,与 Less 的(历史性) less-loader集成误用了 API(使用了 API 的未记录/不受支持的用法),所以这是他们的错误,但我同情人们感到沮丧的是导致构建失败的非主要版本。

就像,如果有人破解了您库中的原型,您如何为此进行防御性编码?

🤷‍♂

@rjgotten

从技术上讲,我在转换后发布了两个 beta 版本,但是……没有人在他们的管道中使用 Less beta。 因此,没有办法测试与 Less 集成的 800,000 个存储库并运行他们的测试。 有了 NPM 依赖项,你真的必须把它放在那里,看看有什么问题。

我们将来可以做的一件事是在测试中添加一些更大的 Less 依赖项,如果我们能弄清楚它们是什么?

我本可以做的另一件事是将它作为主要版本发布,但是.. 从技术上讲,它没有任何(有意的)重大更改,即支持的功能是相同的,并且它包括一些错误修复,所以.. ..我不知道,这是一个棘手的问题。

是的。 这是一个棘手的问题。

我想你可以尝试在.next标签或其他东西上放一些东西,让人们意识到用它来测试他们的构建管道。 但过去的经验表明,这种事情通常是闻所未闻的。

无论哪种方式,无论是否是主要版本,您最终都可能被迫“试一试”,看看有什么问题。

不过不要误会我的意思:重构是一件非常好的事情。 展望未来,它通常应该从维护负担中分得一杯羹。


就像,如果有人破解了您库中的原型,您如何为此进行防御性编码?

你真的没有。

这就像人们抱怨他们精心编排的运行时发出的 IL 来访问 C# 中的私有成员时会跨越次要版本。 如果你插手内部事务,你应该知道你在买什么。 :微笑:

@rjgotten说到重构......

.....随着时间的推移,我在 Less 代码库中发现的一件事是,在许多地方,AST 中的对象存在轻微/微妙的突变。 这里有一个新属性/那里的一个实例上添加了一个方法,我完全承认有时我已经合并了这些功能,因为在 JavaScript 中,你可以随时改变你想要的任何东西,无论你记录/定义该属性与否。

有一些关于 TypeScript 与现代 JS 是否会是答案的讨论。 我已经意识到,没有类型或明确的对象接口使得 Less 代码库有时很难以一种没有任何文档可以解决甚至 JSDocs 可以解决的方式来推理。

我设置了新的管道以允许 TypeScript linting _if_ 你在 JSDoc 中有正确的类型,但是使用 JSDoc 进行打字比 TypeScript 更冗长/视觉上嘈杂,并且有一些打字功能 TS 仅通过 JSDoc 注释不支持. 没有 JSDoc / ESLint 的工具组合可以解决 TS 免费为您提供的一些问题。

所以,我想我想说的是,在去年大量使用 TypeScript 并且在 Less 代码库中花费了数年之后,我想说 95% 的困惑/挫折/学习曲线是弄清楚 Less 是如何工作的如果对象强制执行了编译时类型,则可以避免。 我经常在调试器中花费大量时间,只是设置断点并弄清楚对象的属性_实际上_是什么,而不是它是如何在文件中定义的。

例如,Less 的许多特性在评估期间依赖于Ruleset节点的paths属性。 从这个构造函数中,你能告诉我paths属性是什么,它的形状是什么? (提示:你不能,因为它不存在。)

在 TypeScript(具有通用 tsconfig 设置)中,这是不允许的。 它甚至不会编译。 您将被迫指定paths的形状,以及其中的确切内容,这反过来又会为探索代码库的人提供清晰、具体的文档(和代码提示)。

所以,我想在这一点上,我已经从“TypeScript 是值得考虑的东西”转变为“如果你的公共项目不在 TypeScript 中,那么你就有一大笔技术债务”。 如果没有它,我永远不会启动任何开源 repo,因为它本质上有助于解决消费能力和可维护性。 您仍然需要清晰的文档,但至少它强制执行非常清晰和有凝聚力的编码。

那只是我在思考从这里去哪里,以及未来预防痛点的方法。

_(附录:如果不清楚,我 100% 不会抨击任何人在 Less 代码库中的历史工作。我提出了很多东西,得到了支持,并合并到现在我的代码库中'就像,“哦,我希望我没有那样做,”或者希望我做的不同。而且我当然添加了一些我现在意识到可能会对可维护性产生负面影响的东西。每个人都尽了最大的努力。)_

@matthew-院长
如果您在 JSDoc 中有正确的类型,我设置了新的管道以允许 TypeScript linting,但是使用 JSDoc 进行打字比 TypeScript 更冗长/视觉上嘈杂,并且有一些打字功能 TS 仅通过 JSDoc 注释不支持. 没有 JSDoc / ESLint 的工具组合可以解决 TS 免费为您提供的一些问题。

实际上; 我自己也遇到了 JSDoc 支持对于类型推断来说马马虎虎的问题。
幸运的是,您可以在.js源文件旁边使用.d.ts声明文件,而无需使用完整的 TypeScript 和编译器。

过去使用声明文件要困难得多,但现代版本的 TypeScript 编译器会自动将.d.ts文件与.js $ 文件并排关联,只要两者都被命名相同。

这可能就是你要找的。

@rjgotten你能否解释一下(如果你知道一个好的资源,或者链接),这如何与 Less 的代码库一起工作? 如,您如何按文件级别对文件执行此操作? 每个.js模块是否有.d.ts文件? 还是你把它们分组?

与仅在源代码中使用 TypeScript 相比,拥有.d.ts文件有什么优势? 为什么要花时间制作.d.ts文件,而不是仅仅在文件中定义这些类型?

@rjgotten我今天与 Chevrotain 的开发人员交谈,他说他所做的是在 TS 中开发 _BUT_ 他实际上管理一个api.d.ts文件作为单独的关注点。 这样,源文件(例如树节点)上的任何类型更改都不会透明/不可见地更改公共 API,而无需显式更改 api 类型文件。

然后他使用了一个断言内部类型和公共 API 类型匹配的测试 - > https://github.com/SAP/chevrotain/blob/master/packages/chevrotain/test_integration/definitions/api_type_checking.ts#L1 - L2

Chevrotain 的方式是强制公共 API 不会意外更改的好方法。 非常强大,如果您认为您需要这种级别的保护。 但也会产生一些开销。


关于使用.d.ts声明文件来保存.js类型:
其实两者都是。

如果它们并排运行,那么任何由 TypeScript 编译器支持的用于自动建议、linting 等的 IDE 都将自动获取类型。 Afaik _also_ 如果那些具有并排输入的脚本是从node_modules导入的,那非常好。

您还可以将类型放入单个(一组) .d.ts文件中,例如api.d.ts ,然后使用 JSDoc 显式导入声明的类型。 TypeScript 中的 JSDoc 支持具有@typedef的特殊风格,用于导入语法。 例如

/**
 * <strong i="17">@typedef</strong> {import("../api.d.ts").MyType } MyType
 */

如果您必须在分发之前将包通过转译步骤,则使用单个捆绑的类型文件是一个好主意。 在这种情况下,用户实际上将require()import {}将不再是原始源文件。 即他们不会从并排打字中受益。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

vecerek picture vecerek  ·  5评论

joe223 picture joe223  ·  4评论

seven-phases-max picture seven-phases-max  ·  6评论

awebdev picture awebdev  ·  4评论

renoth picture renoth  ·  6评论