从rollup-plugin-typescript
切换到rollup-plugin-typescript2
以生成声明文件时,不再识别*.vue
文件。
[!] (rpt2 plugin) Error: someFolder/index.ts(2,53): semantic error TS2307 Cannot find module './component.vue'.
src\index.ts
Error: someFolder/index.ts(2,53): semantic error TS2307 Cannot find module './component.vue'.
尝试只导入rollup-plugin-typescript
而不是rollup-plugin-typescript2
包没有问题。
尽管我有最后一个版本(今天确实是每个插件),但这可能与这个问题有关。
你能发布你的 tsconfig 和汇总配置吗?
或者一个带有复制功能的小回购:)
不幸的是,我没有“小”回购。 我在这里工作,试图从webpack
迁移到rollup
。
可以将rollup.config.js
的导入更改为rollup-plugin-typescript2
以查看差异。
你好。
首先非常感谢您为这个插件工作。 它确实比rollup-plugin-typescript
更有意义。
我可以确认此问题存在并设置一个小型演示存储库:
https://github.com/danimoh/rollup-plugin-typescript2-vue-demo
如果您注释掉import AnotherComponent from './AnotherComponent.vue';
它确实可以编译,但不幸的是没有启用该行。
有趣的是,我们大约在同一时间遇到了这个问题。 也许是由最近的变化引起的?
在我对汇总、汇总插件和打字稿知识非常有限的情况下,我的猜测是:
打字稿本身是否可能试图导入AnotherComponent
而不是汇总或rollup-plugin-vue
首先处理该导入?
这将解释为什么rollup-plugin-typescript
没有这个问题,因为它在每个文件的基础上用transpileModule
编译。
在这种情况下,以下内容可能会很有趣: https :
非常感谢有关此问题的任何工作。
在两个 repos 上复制,不确定是否是相同的问题,但很有可能。
为了解决第二种情况,我们确实需要将模块解析发送回汇总,以便 vue 插件可以做到这一点。
连接 rollup 的模块分辨率和打字稿的问题在于,更高版本中的 rollup 会从context.resolveId(...)
返回一个 Promise。 所以调用链看起来像这样:
LanguageService.getEmitOutput
LanguageHost.resolveModuleNames
并期望在该函数中返回解析路径PluginContext.resolveId
LanguageService
似乎是严格同步的: https :
Plugin.transform
本身可以返回一个 Promise,但是链接多个 Promise 的机制使观察者对象上的内部回调深入到我现在无法理解。
有点相关: https :
你好埃佐连科。
现在 Javascript 中的异步方法主要是指返回 Promise 的方法。 新的async
/ await
语法本质上只是异步方法的语法糖,它使开发人员能够编写类似于同步代码的代码, async
方法仍然返回承诺。 await
只能在async
方法中使用。 正如您所注意到的, LanguageHost.resolveModuleNames
方法不是异步的,因此不可能仅在等待纯 Javascript 中的承诺后才从该方法返回。
然而,在 NodeJs 中,通过在当前线程上产生同步方法,然后跳转到异步方法并在异步方法解析时跳转回同步方法,这样的事情实际上是可能的。 请参阅Fibers或它周围的包装器,例如synchronized.js 。
因此,异步方法调用的事情实际上并不是什么大问题。 不过可能还有另一个问题。 虽然插件上下文提供了一个方法resolveId
,但这还不够。 我们需要调用transform
的rollup-plugin-vue
从vue单文件组件中提取typescript代码。 不幸的是,插件上下文似乎没有提供该功能。
解决此问题的一种方法可能是将rollup-plugin-vue
作为依赖项添加到您的项目中,并直接触发 vue 插件上的transform
。 这肯定一点也不漂亮,也不是使用汇总插件的预期方式。
另一种方法可能是在第一次运行时在每个文件的基础上仅在transform
运行transpileModule
以让汇总收集所有导入,让 vue 插件transform
单个文件组件并缓存提取的打字稿代码。 然后在汇总完成之前,丢弃转译的代码并对我们缓存在renderChunk
或generateBundle
插件挂钩中的代码进行适当的打字稿编译。 这可能会干扰其他插件,尽管它们会对我们将丢弃的代码应用额外的转换。
目前我还没有看到更漂亮的解决方案。
编辑:再想一想,第二种方法可能不是_那个_丑陋的。 代替renderChunk
或generateBundle
钩子,插件可以在最后一次导入时检测自己,然后从头开始编译并将编译后的文件添加到汇总队列,以便它实际上也可以由所有其他插件处理。 之前生成的文件仍然需要丢弃,以避免它们最终出现在最终包中。
尽管如此,这种方法还是浪费了一些处理时间,因为它让其他插件也处理我们无论如何都会丢弃的文件。
@danimoh @eddow两个示例存储库的解决方法都使用// @ts-ignore
禁用错误检查,位于违规导入的上方。
错误基本上是打字稿抱怨它不知道 *.vue 东西是什么类型( Cannot find module
表示模块类型)。 一旦静音,一切似乎都可以正确编译。 缺点是从 vue 文件导入的东西具有any
类型并且无助于错误检查。
(在最小 repo 中,第一个组件需要引用第二个组件,否则 rollup treeshash 将其从包中移走)
@danimoh是的,无法通过上下文从汇总中获取模块源。 大部分都可以在 vue 插件端完成(我在那里打开了一个案例),但仍然存在潜在的陷阱,比如 rpt2 需要在转换导入它的脚本之前转换提取的脚本。
我认为您在 vue 问题线程中描述的方法需要打字稿一次处理一个文件,因为它本质上忽略了 vue 文件导入并等待汇总将它们反馈给打字稿。 因此,您会丢失跨文件的类型检查。
作为让 vue 插件处理 ts 的替代方案,以下可能是一种有效的方法,也是我之前提出的丑陋黑客的一种更好的迭代:
options
钩子暴露的吗?transform
方法。CompilerHost
和LanguageServiceHost
可以自定义fileExists
、 readFile
、 getScriptSnapshot
等。.vue
文件,则从 vue 插件中请求它们。 对于所有 vue 文件,我们缓存提取的打字稿代码并覆盖诸如readFile
以返回缓存的 ts 代码以进行vue
导入。编辑:实际上,如果我们可以覆盖fileExists
和readFile
,我们就不需要通过遍历 AST 自己收集导入,因为打字稿只是要为它想要导入的所有导入调用这些方法无论如何。 然后我们只需要按需调用 vue 插件。
Vue 插件实例可能已暴露,我不知道 rollup 是否希望插件相互调用,以及在这种情况下是否会中断(立即或将来)。
你的第二点会起作用,这正是LanguageServiceHost
的用途。
这种方法可能有效,主要的缺点是与 vue 插件的耦合可能很脆弱,以及一次性工作的额外周期。
我希望汇总有一种方法可以让插件中止转换并在重试当前文件之前声明要转换的依赖项,然后这可以干净地实现......
我认为实际上没有一次性工作。 Typescript 只会编译一次代码,如果我们缓存提取的 ts 代码,vue 插件也只需要处理每个文件一次。 除了我之前的建议之外,这种方法不会丢弃任何它自己的结果或其他插件的结果。
是的,汇总时需要进行一些架构更改。 也许人们可以在那里打开一个问题来实施这样的事情,但这可能需要很长时间。
我也不确定它是否真的让事情变得更好。 我们仍然必须确保打字稿一次编译整个内容以对所有文件进行类型检查。 否则我们也可能会遇到这个。
它适用于我的这个设置,编译单个 vue 组件:
import VuePlugin from 'rollup-plugin-vue'
import typescript from 'rollup-plugin-typescript2'
export default {
plugins: [
typescript({
typescript: require('typescript'),
objectHashIgnoreUnknownHack: true,
}),
VuePlugin(/* VuePluginOptions */),
],
input: 'src/components/HelloWorld.vue',
output: [
{ file: 'dist/HelloWorld.cjs.js', format: 'cjs' },
{ file: 'dist/HelloWorld.esm.js', format: 'esm' },
],
}
我不确定这是否是使用 lang="ts" 从 Vue SFC 创建模块的最佳方式。
它适用于我的这个设置,编译单个 vue 组件:
是的,但这不是一个真正的用例。 那是你好世界。 对于任何无法理解问题的人,以下是我收集到的内容。
为什么? 这是一个例子:
<script lang="ts">
import Bar from './Bar.vue';
...
</script>
1) vue 插件将脚本传递给 typescript 插件
2) typescript 插件遇到一个.vue
文件,但无法知道如何处理它,因为 rollup 没有提供一种机制让插件在导入时遵循其他插件,如 webpack。 常规 JS 可以服从插件,但已经被插件处理的代码不能。
3)我实际上不明白为什么这与lang=scss
或lang=ts
,但我猜是这样。
好吧,我能做什么?
不多。
但是验证! 好!
Vuetify 是打字稿,但不使用 SFC。 它是纯粹的渲染功能。
Buefy 使用 SFC 和汇总,但没有打字稿。
真的,我什么都做不了?
你不会喜欢的。 对于需要从打字稿文件导入的每个 Vue 文件,您必须创建一个常规的 javascript 文件中介。
import Bar from './Bar.vue';
export default Bar;
只有这样,您才能使用汇总构建您的打字稿 SFC 组件库。
天哪,真烂
如果您提出了更好的解决方案,我很乐意听到。
最有用的评论
是的,但这不是一个真正的用例。 那是你好世界。 对于任何无法理解问题的人,以下是我收集到的内容。
rollup 字面上不能做到这一点
为什么? 这是一个例子:
1) vue 插件将脚本传递给 typescript 插件
2) typescript 插件遇到一个
.vue
文件,但无法知道如何处理它,因为 rollup 没有提供一种机制让插件在导入时遵循其他插件,如 webpack。 常规 JS 可以服从插件,但已经被插件处理的代码不能。3)我实际上不明白为什么这与
lang=scss
或lang=ts
,但我猜是这样。不多。
Vuetify 是打字稿,但不使用 SFC。 它是纯粹的渲染功能。
Buefy 使用 SFC 和汇总,但没有打字稿。
你不会喜欢的。 对于需要从打字稿文件导入的每个 Vue 文件,您必须创建一个常规的 javascript 文件中介。
只有这样,您才能使用汇总构建您的打字稿 SFC 组件库。
如果您提出了更好的解决方案,我很乐意听到。