Rollup-plugin-typescript2: Ver arquivo de importação

Criado em 9 jan. 2019  ·  14Comentários  ·  Fonte: ezolenko/rollup-plugin-typescript2

Ao mudar de rollup-plugin-typescript para rollup-plugin-typescript2 para produzir arquivos de declaração, os arquivos *.vue não são mais reconhecidos.

[!] (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'.

Tentar apenas importar rollup-plugin-typescript vez de rollup-plugin-typescript2 pacotes sem problemas.

Isso pode estar relacionado a esse problema, embora eu tenha a última versão (de todos os plugins atuais, na verdade).

bug help wanted

Comentários muito úteis

Funciona para mim com esta configuração, para compilar um único componente vue:

Certo, mas esse não é um caso de uso real. Isso é olá, mundo. Para qualquer pessoa com problemas para entender o problema, aqui está o que descobri.

rollup literalmente não pode fazer isso

porque? aqui está um exemplo:

<script lang="ts">
import Bar from './Bar.vue';
...
</script>

1) o plugin vue passa o script para o plugin typescript
2) o plug-in typescript encontra um arquivo .vue , mas não tem como saber o que fazer com ele porque o rollup não fornece um mecanismo para que os plug-ins sejam transferidos para outros plug-ins em importações como webpack. JS regular pode adiar para plug-ins, mas o código que já está sendo processado por um plug-in não pode.
3) Na verdade, não entendo por que isso é diferente de lang=scss ou lang=ts , mas acho que é.

Bem, o que posso fazer?

Não muito.

Mas vuetifique! buefy!

Vuetify é digitado, mas não usa SFCs. São funções puras de renderização.

Buefy usa SFCs e rollup, mas nenhum texto digitado.

Sério, não há nada que eu possa fazer?

Você não vai gostar. Para cada arquivo Vue que você precisa importar de um arquivo typescript, você terá que criar um intermediário de arquivo javascript regular.

import Bar from './Bar.vue';

export default Bar;

Então, e somente então, você será capaz de construir sua biblioteca de componentes SFC de script com rollup.

Nossa, isso é péssimo

Se você encontrou uma solução melhor, adoraria ouvi-la.

Todos 14 comentários

Você poderia postar seu tsconfig e configuração de rollup?

Ou um pequeno repo com reprodução :)

Infelizmente, não tenho um repositório "pequeno". Estou trabalhando aqui , tentando migrar de webpack para rollup .

A importação em rollup.config.js pode ser alterada para rollup-plugin-typescript2 para ver a diferença.

Olá.

Em primeiro lugar, muito obrigado por trabalhar neste plugin. Na verdade, faz muito mais sentido do que rollup-plugin-typescript .

Posso confirmar que esse problema existe e configurar um pequeno repositório de demonstração:
https://github.com/danimoh/rollup-plugin-typescript2-vue-demo

Se você comentar a linha import AnotherComponent from './AnotherComponent.vue'; ela compila, mas infelizmente não com esta linha habilitada.

É engraçado que encontramos esse problema na mesma época. Talvez tenha sido causado por uma mudança recente?
Uma suposição da minha parte com conhecimento muito limitado sobre rollup, plug-ins de rollup e texto digitado seria:
É possível que o próprio typescript esteja tentando importar AnotherComponent vez de rollup ou rollup-plugin-vue tratando dessa importação primeiro?

Isso explicaria por que rollup-plugin-typescript não tem esse problema, pois compila por arquivo com transpileModule .

Nesse caso, o seguinte pode ser interessante: https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#customizing -module-resolution

Qualquer trabalho sobre este assunto é muito apreciado.

Reproduzido em ambos os repositórios, não tenho certeza se é o mesmo problema ainda, mas é provável.

Para consertar o segundo caso, realmente precisamos enviar a resolução do módulo de volta ao rollup para que o plugin vue possa fazer isso.

O problema de conectar a resolução do módulo de rollup e o texto digitado é que o rollup em versões posteriores retorna uma promessa de context.resolveId(...) . Portanto, a cadeia de chamadas se parece com isto:

  • rollup chama a transformação do plugin
  • plugin chama LanguageService.getEmitOutput typescript
  • o serviço de linguagem chama a implementação do plugin de LanguageHost.resolveModuleNames e espera que os caminhos resolvidos sejam retornados nessa função
  • acúmulo de chamadas do host PluginContext.resolveId
  • rollup retorna uma promessa
  • se entendi bem, tudo que posso fazer com uma promessa é fazer outra promessa

LanguageService parece ser estritamente síncrono: https://github.com/Microsoft/TypeScript/issues/1857

Plugin.transform pode retornar uma promessa, mas a mecânica de encadear várias promessas feitas em callbacks em um objeto observador me foge no momento.

Olá ezolenko.

Hoje em dia, os métodos assíncronos em Javascript significam principalmente métodos que retornam Promises. A nova sintaxe async / await é essencialmente apenas açúcar sintático para métodos assíncronos que permite ao desenvolvedor escrever seu código semelhante ao código síncrono, métodos async ainda retornam promessas. await entanto, async . Como você notou, o método LanguageHost.resolveModuleNames não é assíncrono e, portanto, não é possível retornar desse método somente após esperar por uma promessa em Javascript simples.

No entanto, em NodeJs, coisas como essa são realmente possíveis produzindo o método síncrono no encadeamento atual e, em seguida, saltando para o método assíncrono e voltando para o método síncrono quando o método asynchronoues for resolvido. Veja Fibras ou invólucros em torno dele, como synchronize.js .

Assim, a invocação do método assíncrono não é um grande problema. No entanto, pode haver outro problema. Embora o contexto do plugin ofereça um método resolveId , isso não será suficiente. Precisamos chamar transform de rollup-plugin-vue para extrair o código de digitação dos componentes de arquivo único vue. O contexto do plugin não parece oferecer essa funcionalidade, infelizmente.

Uma abordagem para resolver isso pode ser adicionar rollup-plugin-vue como uma dependência ao seu projeto e acionar o plug-in transform diretamente no vue. Isso com certeza não é nada bonito e não é a maneira pretendida de trabalhar com plug-ins cumulativos.

Outra abordagem pode ser executar apenas transpileModule em transform por arquivo em uma primeira execução para permitir que o rollup colete todas as importações, deixe o plugin vue transform o single componentes do arquivo e armazenar em cache o código datilografado extraído. Então, antes que o rollup termine, descarte o código transpilado e faça uma compilação de texto digitado adequada no código que armazenamos em cache em um gancho de plugin renderChunk ou generateBundle Isso pode interferir com outros plug-ins, embora apliquem transformações adicionais ao código que nós descartamos.

Por enquanto não vejo uma solução mais bonita ainda.

Edit: Pensando bem, a segunda abordagem talvez não seja _tão_ feia. Em vez de renderChunk ou generateBundle ganchos, o plug-in pode detectar a si mesmo quando a última importação está sendo importada e, nesse ponto, iniciar a compilação do zero e adicionar o arquivo compilado à fila de rollup para que também pode ser processado por todos os outros plug-ins. Os arquivos gerados anteriormente ainda precisam ser descartados para evitar que eles acabem no pacote final.
Ainda assim, essa abordagem desperdiça algum tempo de processamento, pois permite que os outros plug-ins também estejam em arquivos que iríamos descartar de qualquer maneira.

@danimoh @eddow A solução alternativa para ambos os exemplos de // @ts-ignore logo acima das importações ofensivas.

O erro é basicamente datilografado reclamando que não sabe que tipo * .vue stuff é ( Cannot find module significa tipo de módulo). Uma vez que isso é silenciado, tudo parece compilar corretamente. A desvantagem é que as coisas importadas de arquivos vue têm o tipo any e não ajudam na verificação de erros.

(no repositório mínimo, o primeiro componente precisa de uma referência ao segundo, caso contrário, a árvore de rollup o afasta do pacote)

@danimoh sim, nenhuma maneira de obter a fonte do módulo do rollup via contexto. A maior parte disso pode ser feito no lado do plugin vue (abri um caso lá), mas ainda existem armadilhas potenciais, como rpt2 precisará ter transformado o script extraído antes de transformar um script que o importa.

Eu acho que a abordagem que você descreve no tópico vue issue requer a digitação para processar os arquivos um de cada vez, pois essencialmente ignora as importações do arquivo vue e aguarda o rollup para alimentá-los de volta ao datilografado. Portanto, você perderia a verificação de tipos nos arquivos.

Como alternativa para deixar o plug-in vue lidar com ts, o seguinte pode ser uma abordagem válida e uma espécie de iteração melhor dos hacks feios que propus anteriormente:

  • A instância do plugin vue está exposta por meio do gancho options ?
    Dessa forma, poderíamos chamar o método transform no plugin vue.
  • De https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API , parece-me que os ts CompilerHost e LanguageServiceHost podem ser alimentados de forma personalizada fileExists , readFile , getScriptSnapshot e semelhantes.
  • Se ambos funcionassem, poderíamos deixar o typescript analisar o código que obtemos do plug-in vue para um AST e coletar as importações desse AST e solicitá-las do plug-in vue se forem arquivos .vue . Para todos os arquivos vue, armazenamos em cache o código de digitação extraído e métodos de substituição, como readFile para retornar o código ts armazenado em cache para uma importação de vue .

Edit: Na verdade, se pudermos sobrescrever fileExists e readFile , não precisaremos coletar as importações por nós mesmos percorrendo o AST, pois o texto digitado apenas chamará esses métodos para todas as importações que deseja importar enfim. Em seguida, precisamos apenas chamar o plugin vue sob demanda.

A instância do plug-in Vue provavelmente está exposta, não sei se o rollup espera que os plug-ins chamem uns aos outros e se algo irá falhar (imediatamente ou no futuro) nesse caso.

Seu segundo ponto funcionará, é exatamente para isso que serve LanguageServiceHost .

Essa abordagem pode funcionar, a principal desvantagem sendo o acoplamento potencialmente frágil com o plugin vue e ciclos extras para trabalho descartável.

Eu gostaria que o rollup tivesse uma maneira de os plug-ins abortarem a transformação e declararem uma dependência a ser transformada antes de o arquivo atual ser tentado novamente, então isso poderia ser implementado de forma limpa ...

Acho que na verdade não há trabalho descartável. O typescript apenas compilará o código uma vez e também o plugin vue precisará processar cada arquivo apenas uma vez se armazenarmos em cache o código ts extraído. Essa abordagem não descarta nenhum de seus próprios resultados ou resultados de outros plug-ins além da minha sugestão anterior.

Sim, alguma mudança arquitetônica seria necessária no rollup. Talvez alguém pudesse abrir um problema lá para implementar algo assim, mas provavelmente levaria séculos.
Além disso, não tenho certeza se isso torna as coisas realmente muito melhores. Ainda temos que garantir que o texto digitado compila tudo de uma vez para fazer a verificação de tipos em todos os arquivos. Caso contrário, também podemos topar com isso .

Funciona para mim com esta configuração, para compilar um único componente 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' },
  ],
}

Não tenho certeza se esta é a melhor maneira de criar um módulo a partir de um Vue SFC com lang = "ts".

Se alguém tiver algum conselho, por favor me avise.

Funciona para mim com esta configuração, para compilar um único componente vue:

Certo, mas esse não é um caso de uso real. Isso é olá, mundo. Para qualquer pessoa com problemas para entender o problema, aqui está o que descobri.

rollup literalmente não pode fazer isso

porque? aqui está um exemplo:

<script lang="ts">
import Bar from './Bar.vue';
...
</script>

1) o plugin vue passa o script para o plugin typescript
2) o plug-in typescript encontra um arquivo .vue , mas não tem como saber o que fazer com ele porque o rollup não fornece um mecanismo para que os plug-ins sejam transferidos para outros plug-ins em importações como webpack. JS regular pode adiar para plug-ins, mas o código que já está sendo processado por um plug-in não pode.
3) Na verdade, não entendo por que isso é diferente de lang=scss ou lang=ts , mas acho que é.

Bem, o que posso fazer?

Não muito.

Mas vuetifique! buefy!

Vuetify é digitado, mas não usa SFCs. São funções puras de renderização.

Buefy usa SFCs e rollup, mas nenhum texto digitado.

Sério, não há nada que eu possa fazer?

Você não vai gostar. Para cada arquivo Vue que você precisa importar de um arquivo typescript, você terá que criar um intermediário de arquivo javascript regular.

import Bar from './Bar.vue';

export default Bar;

Então, e somente então, você será capaz de construir sua biblioteca de componentes SFC de script com rollup.

Nossa, isso é péssimo

Se você encontrou uma solução melhor, adoraria ouvi-la.

Esta página foi útil?
0 / 5 - 0 avaliações