Three.js: A importação de exemplos de módulos jsm faz com que os bundlers agrupem o código-fonte three.js duas vezes

Criado em 12 set. 2019  ·  43Comentários  ·  Fonte: mrdoob/three.js

Importar de three/examples/jsm/.../<module> faz com que os bundlers (testados com rollup) incluam a biblioteca duas vezes (ou várias vezes).

Por exemplo, ao fazer import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' , o bundler seguirá a importação e no OrbitControls.js as importações virão de ../../../build/three.module.js . No entanto, não há como o empacotador (externo) saber que ../../../build/three.module.js é o mesmo módulo que three .

Uma solução para isso seria tratar os módulos de exemplo como pacotes externos e importar de three vez de ../../../build/three.module.js . Isso pode quebrar a configuração de rollup de three.js, mas deve ser possível dizer ao rollup que three é um apelido para o ponto de entrada principal de três ( src/Three.js ).

Comentários muito úteis

Acho que é apenas algo para se acostumar. Agora que acho que entendi, estou bem do jeito que está.

BTW, atualizei três fundamentos para todos serem baseados em ESM, então 🤞

Todos 43 comentários

(testado com rollup)

Não posso confirmar isso com rollup. Se você estiver fazendo isso como na configuração do projeto a seguir, tudo funcionará conforme o esperado.

https://github.com/Mugen87/three-jsm

Se você tratar three como dependência externa:

export default {
    input: 'src/main.js',
    external: ['three'],
    output: [
        {
            format: 'umd',
            name: 'LIB',
            file: 'build/main.js'
        }
    ],
    plugins: [ resolve() ]
};

então, a saída não deve conter o código-fonte de three.js, mas inclui tudo.

Se, entretanto, você não importar os OrbitControls, a saída incluirá apenas o código-fonte do arquivo main.js .

você pode experimentar comentando a importação OrbitControls e, em seguida, 'three' como dependência externa).

Isso está relacionado a # 17220 - uma das soluções propostas era substituir o campo main em package.json pelo caminho de construção do módulo, mas isso não resolveria este caso de uso.

Só para ficar claro, o problema aqui é que enquanto three está sendo marcado como externo para construir um pacote separado que é dependente de três na configuração de rollup que não pega a referência dura a ../../../build/three.module.js e inclui-o na construção. Por exemplo, construir o arquivo a seguir incluirá inadvertidamente o código OrbitControls _and_ o código threejs no pacote, bem como importará outra cópia de três quando construído com a configuração postada de @adrian-delgado.

// src/main.js
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

console.log(THREE, OrbitControls);

@adrian-delgado pode ser importante notar que mesmo se o caminho em OrbitControls.js for alterado para three OrbitControls ainda serão incluídos em seu pacote, o que pode ou não ser desejado e pode resultar em pelo menos o código OrbitControls sendo incluído duas vezes em aplicativos dependentes.

Não pretendo propor isso como uma solução de longo prazo ou melhor, mas alterar a configuração para marcar OrbitControls (e todos os arquivos nas três pastas) como externos resolveria isso em ambos os casos:

export default {
    // ...

    external: p => /^three/.test(p),

    // ...
};

Não pretendo propor isso como uma solução de longo prazo ou melhor, mas alterar a configuração para marcar OrbitControls (e todos os arquivos nas três pastas) como externos resolveria isso em ambos os casos:

Por alguma razão, eu esperava que o rollup tratasse 'three/examples/jsm/controls/OrbitControls.js' como externo também por padrão. Portanto, a solução proposta é boa para o meu caso de uso.

O # 17220 relacionado é muito relevante. A conversa provavelmente deve continuar aí.

Então, o que acontece se você fizer isso?

// src/main.js
import * as THREE from 'three/build/three.module.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

console.log(THREE, OrbitControls);

Funcionaria, mas não é viável, porque qualquer outra biblioteca ou parte de código que dependa de três será importada de "três" e, em seguida, quebrará novamente. Package.json normalmente diz ao ambiente como resolver, "build / three.module" é um detalhe de distribuição que não deve vazar. Quando a resolução é ignorada, isso só atrai problemas de namespace.

  external: p => /^three/.test(p),

@gkjohnson E se o usuário quiser incluir a instância "três" e OrbitControls no pacote?

Não tenho certeza se está relacionado, um semelhante acontece se você tentar usar módulos ao vivo como este

import * as three from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.module.js';
import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';

carrega three.js duas vezes, uma do CDN e novamente de threejs.org

Talvez não seja assim que os módulos devem ser usados ​​com três, mas indo desde antes do 106, há milhares de sites e exemplos que

<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/105/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>

Todos os exemplos mostram o uso de módulos ao vivo em vez de construção (empacotamento), portanto, de certa forma, eles não estão mostrando a maneira real de usar o three.js como costumavam fazer. Em outras palavras, os exemplos antigos funcionaram imediatamente. Os novos exemplos não AFAIK. Para que um exemplo funcione, você precisa extrair o JavaScript do exemplo e colocá-lo em um arquivo .js separado e, em seguida, colocar three.js localmente (provavelmente via npm). Corrija todos os caminhos nos exemplos para que sejam caminhos baseados em pacote (não ../.././build) e, finalmente, use o rollup

Essa é uma mudança muito grande em relação às versões não modulares, para as quais apenas alterar os caminhos foi o suficiente

@mrdoob

Com a configuração original de @adrian-delgado, o three.js será incluído uma vez e os controles de órbita serão incluídos uma vez e nenhum pacote será marcado como externo. Com a configuração que propus, haverá uma dependência externa de three/build/three.module.js e three/examples/jsm/controls/OrbitControls.js no pacote produzido.

@EliasHasle

E se o usuário quiser incluir a instância "três" e OrbitControls no pacote?

Em seguida, o campo external deve ser excluído, caso em que uma única cópia de três e controles de órbita serão incluídos no pacote. rollup-plugin-node-resolve (que é necessário para rollup para suportar resolução de módulo e está sendo usado nas configurações acima) padrões para usar o campo de módulo de package.json (veja a opção mainFields ) para a órbita controla três referências e "três" resolverá para o mesmo script. _Se mainFields for alterado para ["main", "module"] então "principal" é usado em vez de "módulo" em package.json_, então duas cópias de três serão incluídas aqui e as coisas vão quebrar da maneira que antes mencionado anteriormente. No entanto, é necessário alterar esse campo. Se "main" for usado, entretanto, rollup-plugin-commonjs provavelmente precisará ser necessário também, porque rollup não sabe como processar arquivos commonjs que usam require por padrão.

@greggman

Infelizmente, não acho que uma substituição ingênua de módulos funcione tão facilmente neste caso. Nenhuma das soluções propostas abordará esse caso e não acho que haja nada oficial no momento que possa ser usado para ajudar no caso de importação do script principal e do exemplo de hosts separados. Mapas de importação são a única coisa que está em desenvolvimento para ajudar com isso, pelo que eu sei. Se o exemplo e três forem importados do mesmo host, apenas uma única cópia de três será carregada:

import * as three from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.module.js';
import { OrbitControls } from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/108/examples/jsm/controls/OrbitControls.js';

// or

import * as three from 'https://threejs.org/build/three.module.js';
import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';

Dependendo do caso de uso, talvez seja preferível continuar usando as tags de script clássicas?

@greggman

Não tenho certeza se está relacionado, um semelhante acontece se você tentar usar módulos ao vivo como este

import * as three from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.module.js';
import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';

Sim ... Não use módulos assim 😁

Sim ... Não use módulos assim 😁

Concordou. É apenas indiscutível que os documentos e exemplos são direcionados principalmente a desenvolvedores inexperientes e o fato de que os exemplos jsm são o padrão e nenhum deles funcionará sem um construtor nem através de qualquer CDN é uma grande mudança.

Antigamente, você basicamente podia ver o código-fonte em um exemplo, copiar e colar em jsfiddle / codepen etc, corrigir os caminhos nas tags do script e ele seria executado. Agora, embora todos os exemplos não sejam executados, a menos que você se conecte diretamente ao site three.js e os observe quebrar cada vez que a versão for alterada. (sim, eu sei que existem exemplos não modulares, mas esses não são aqueles vinculados a https://threejs.org/examples)

@gkjohnson

import * as three from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.module.js';
import { OrbitControls } from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/108/examples/jsm/controls/OrbitControls.js';

Não funciona, OrbitControls não está no CDN e os caminhos dentro de OrbitContrls ../../../bulild/three.js não é o caminho correto para fazê-lo funcionar

// ou

import * as three from 'https://threejs.org/build/three.module.js';
import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js'

Também não funciona, pois vai quebrar toda vez que three.js colocar uma nova versão

Talvez enviar a pasta examples / js para um CDN e três de forma que apenas corrigir os urls no código de exemplo ainda funcione? Isso significa que three.module.js precisa estar em

https://cdnjs.cloudflare.com/ajax/libs/three.js/108/build/three.module.js

build adicionado ao caminho

Antigamente, você basicamente podia ver o código-fonte em um exemplo, copiar e colar em jsfiddle / codepen etc, corrigir os caminhos nas tags do script e ele seria executado ...

Acho que precisaremos importar mapas para fazer algo útil a respeito, para melhor ou pior.

Agora, embora todos os exemplos não sejam executados a menos que você vincule diretamente ao site three.js

Eu realmente não encorajaria ninguém a criar um link direto para scripts ao vivo no site threejs ... isso nunca será uma boa ideia. Existem alternativas com versão, conforme o comentário acima.

A documentação que idealmente responderia a essas perguntas é a página Importar via módulos . Existem casos que devemos cobrir lá? Suponho que mencionar os CDNs seria uma boa ideia.

Mencionar os CDNs seria uma boa ideia. Mencionando também que o cloudflare CDN, o primeiro hit, no Google não é bom para módulos (a menos que isso mude)

@greggman

Antigamente, você basicamente podia ver o código-fonte em um exemplo, copiar e colar em jsfiddle / codepen etc, corrigir os caminhos nas tags do script e ele seria executado.

Estou no seu lado. A pior parte dos módulos é que você não pode mais acessar camera ou renderer do console nos exemplos 😟

Que tal começarmos a usar o unpkg?

Quer dizer começar a usá-lo em documentação como a página Importar via módulos , ou usá-lo no projeto de alguma forma?

A pior parte dos módulos é que você não pode mais acessar a câmera ou o renderizador do console nos exemplos

Sim, isso é frustrante. Eu tenho jogado isso (ou algo semelhante) nos exemplos ao desenvolver localmente:

Object.assign( window, { camera, renderer, scene } );

Presumo que isso seja algo que esperamos resolver com uma extensão de ferramentas de desenvolvimento.

Uma ideia que exigiria alguma investigação, mas poderia ser interessante ... se estivéssemos dispostos a adicionar um polyfill de mapa de importação a todos os exemplos, acho que poderíamos fazer as importações usadas lá 100% copiar / colar compatível com npm- e fluxos de trabalho baseados em bundler. Por exemplo:

<script defer src="es-module-shims.js"></script>
<script type="importmap-shim" src="importmap.dev.js"></script>

<!-- ... -->

<script type="module-shim">
  import { Scene, WebGLRenderer } from 'three';
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

  // ...
</script>

Que tal começarmos a usar o unpkg?

Quer dizer começar a usá-lo em documentação como a página Importar via módulos, ou usá-lo no projeto de alguma forma?

Em vez de apontar para https://threejs.org/build/. Atualmente, estamos usando esse link em ISSUE_TEMPLATE .

E @greggman provavelmente poderia mudar de https://cdnjs.cloudflare.com/ajax/libs/three.js/108/ para https://unpkg.com/[email protected]/ ?

Parece que descompactar resolve os problemas que estamos discutindo aqui.

Sim, isso é frustrante. Eu tenho jogado isso (ou algo semelhante) nos exemplos ao desenvolver localmente:

Object.assign( window, { camera, renderer, scene } );

ECA! Haha

Presumo que isso seja algo que esperamos resolver com uma extensão de ferramentas de desenvolvimento.

Sim! 🤞

@greggman

Não tenho certeza se está relacionado, um semelhante acontece se você tentar usar módulos ao vivo como este

import * as three from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.module.js';
import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';

Sim ... Não use módulos assim 😁

Então, hoje eu me peguei fazendo exatamente isso ... 😅 É um mau hábito, de fato, mas o problema é que a maioria das coisas meio que funciona, mas se algo quebrar é muito difícil de resolver.

No meu caso, eu estava importando three.module.js de dev e OBJLoader de master . OBJLoader importou three.module.js de master então BufferGeometry não tinha a nova propriedade usage e WebGLRenderer tinha não renderizar a malha porque não encontrou usage , mas tudo o mais funcionou 😶

Isso é muito peludo ...

Acho que é apenas algo para se acostumar. Agora que acho que entendi, estou bem do jeito que está.

BTW, atualizei três fundamentos para todos serem baseados em ESM, então 🤞

Parece que seria bom ter um three.module.min.js embora (ou isso é three.min.module.js 😜)

+1

Estou apenas importando três controles de & orbit como módulos ES6 & porque (parece) os controles de orbit se referem a três dentro da pasta de construção, demorei um pouco para descobrir meus caminhos

Super fã podemos usar três como módulos, mas seria bom ter mais flexibilidade em torno disso, não vou entrar no arquivo de controles de órbita e começar a mexer nisso, supondo que este seja o caso com outros módulos também.

Também +1 para three.min.module.js 😎

movendo-se de # 18239, eu fui pego nele um problema semelhante, fazendo npm link em outro pacote que usa three.js.

Desenvolvi um plugin de três minificador que pode ajudar a resolver esse problema.

Estou enfrentando o mesmo problema. Estou escrevendo um componente React usando three.js e estou importando alguns módulos dos exemplos. Depois de agrupado com rollup, se eu olhar para o pacote, posso ver que há uma instrução de importação para três e, em seguida, o código Three.js.

Se eu usar esta declaração de importação em meu componente: import * as THREE from "three/build/three.module"
as coisas funcionam corretamente, mas o Three é incorporado ao pacote, o que é algo que eu não quero.
Eu gostaria de ter uma declaração de importação para três. Se eu usar import * as THREE from "three , o pacote terá três importados como um módulo, mas assim que eu usar um dos exemplos, então three.js é adicionado ao pacote (= eu tenho uma instrução de importação para três, e, em seguida, o código de três), o que acaba por causar a quebra do meu código

@chabb

Estou escrevendo um componente React usando three.js e estou importando alguns módulos dos exemplos. Depois de agrupado com rollup, se eu olhar para o pacote, posso ver que há uma instrução de importação para três e, em seguida, o código Three.js.

A solução postada aqui deve resolver seu problema: https://github.com/mrdoob/three.js/issues/17482#issuecomment -530957570.

Acho que muitos desses problemas são derivados de pessoas que não entendem totalmente o que está acontecendo com seu bundler (o que é compreensível), mas esses problemas não são exclusivos de três. É possível, entretanto, que a importação dupla acidental de três núcleos seja apenas mais perceptível do que com outras bibliotecas. Empacotar uma dependência que deve ser externa, como lodash, um componente react ou OrbitControls, pode simplesmente passar despercebido.

Com relação à dependência de um pacote externo, o Rollup documenta esse comportamento e fornece uma opção aqui e o Webpack tem uma opção semelhante aqui . Neste caso, se os arquivos de exemplo em vez disso se referissem a "três", enquanto a biblioteca principal não fosse agrupada, você ainda obteria pacotes duplicados de código de exemplo, o que é um problema próprio. E não acho que haja nada que este projeto possa fazer para ajudar um bundler a interpretar as armadilhas do link npm. Acho que o único caso problemático que vi que sinto que não é o resultado de um bundler mal configurado é o caso codesandbox.

Para os casos de bundler, talvez a resposta seja documentar, adicionar um guia de solução de problemas ou link para como configurar os bundlers comuns na página de importação via módulos .

Tenho um palpite de que se examples/jsm pacotes pudessem mudar esse padrão ...

// <strong i="7">@file</strong> GLTFLoader.js

// Before
import { Mesh } from '../../build/three.module.js';

// After
import { Mesh } from 'three';

... esses problemas seriam muito mais fáceis de resolver. Infelizmente, não sei como gerenciaríamos os exemplos de HTML no site do threejs sem uma configuração de compilação complexa. Um polyfill de mapa de importação no site threejs pode resolver isso, mas não tenho certeza. : /

se os arquivos de exemplo se referissem a "três", então, embora a biblioteca principal não fosse empacotada, você ainda obteria pacotes duplicados de código de exemplo ...

Eu não entendo bem isso. Porque são importações de caminho relativo? Poderíamos torná-los relativos ao pacote.

@donmccurdy

Tenho um palpite de que se os pacotes examples / jsm pudessem mudar esse padrão ... esses problemas seriam muito mais fáceis de resolver.

Eu acho que isso faria com que parecesse resolvido, mas as pessoas ainda teriam código duplicado que é apenas mais difícil de notar porque não causa a falha do aplicativo.

Eu não entendo bem isso. Porque são importações de caminho relativo? Poderíamos torná-los relativos ao pacote.

Desculpe se não estou claro, acho que isso é um pouco difícil de explicar - espero que seja um pouco mais claro. Vou usar o caso Rollup:

Nos casos acima, em que as pessoas desejam acumular um pacote com three marcado como externo, presumo que eles estejam construindo uma biblioteca em que three.js seria uma dependência de ponto em que outro aplicativo poderia contar:

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { stuff } from './local/src/index.js';

// library code with exports...

Aqui, o objetivo seria que as importações de three.js acima permanecessem na biblioteca e o pacote carregasse três e OrbitControls como dependências de pares, portanto, se o aplicativo também usar three.js e OrbitControls, você não importaria nenhum deles duas vezes.

As pessoas esperam que a opção external: [ 'three' ] atinja esse comportamento para elas (eu certamente fiz), mas isso não aconteceu porque a string não corresponde ao caminho de importação OrbitControls. Isso resulta em OrbitControls sendo empacotado involuntariamente e, portanto, ../../../build/three.module.js sendo empacotado também (porque também não corresponde à string). Acho que as pessoas apontam para o arquivo principal three.js sendo empacotado porque é muito mais perceptível - a quebra de aplicativos, o pacote de biblioteca é muito maior, etc - onde a realidade é que _o arquivo OrbitControls não deveria ter sido empacotado no primeiro lugar._ A maneira correta de configurar o Rollup aqui é definir a opção como external: path => /^three/.test( path ) .

Isso não é exclusivo para três. Rollup usa lodash como exemplo em seus documentos, mas será difícil / impossível notar se 'lodash/merge' for agrupado em seu código de biblioteca por ser tão pequeno e não causar erros de importação duplicados. A IU de material incentiva referências de arquivo aninhadas nas importações e, da mesma forma, a configuração external: ['@material-ui/core'] deixaria de excluir '@material-ui/core/Button' do pacote.

Não acho que valha a pena alterar o código de exemplo para esses casos de uso porque ainda resultará em código duplicado que não estaria lá se o bundler fosse configurado corretamente.

Dois casos aqui:

(1) o usuário deseja três js e exemplos incluídos uma vez, obtém algo duas vezes

Por exemplo, durante a construção de um aplicativo.

(2) o usuário quer três js e os exemplos incluídos zero vezes, obtém algo 1+ vezes

Por exemplo, ao construir uma biblioteca com três como dependência externa ou de par.


Pelo que eu sei, (1) e (2) ainda são problemas fáceis de encontrar? Se a abordagem acima resolver (1), isso por si só é útil. Não tenho certeza sobre (2). Talvez o truque /^three/.test( path ) deva ser mencionado na importação via módulos ?

@gkjohnson Obrigado por esta explicação, realmente me ajudou a esclarecer meus pensamentos

Na minha configuração de rollup, eu estava definindo external desta forma

[
        ...Object.keys(pkg.dependencies || {}),
        ...Object.keys(pkg.peerDependencies || {}),
        ...other_stuff
      ]

Achei que funcionaria, já que três seriam tratadas como dependências externas; mas como você mencionou, você tem que usar uma regex (pelo que eu entendo, acho que é porque os exemplos estão fazendo
import from "../../../build/three.module.js"; ). Então acabei fazendo

external: p => {
      if ([
        ...Object.keys(pkg.dependencies || {}),
        ...Object.keys(pkg.peerDependencies || {}),
        'prop-types'
      ].indexOf(p) > -1) {
        return true;
      }
      return /^three/.test(p) ;
    }

É uma questão um pouco não relacionada, mas eu esperaria que todas as dependências que declarei em package.json não façam parte do pacote. É uma suposição correta?

@donmccurdy

Pelo que eu sei, (1) e (2) ainda são problemas fáceis de encontrar?

Na minha opinião (2) é o resultado da configuração incorreta do bundler e talvez possamos resolver isso atualizando os documentos com algumas sugestões para bundlers. (1) pode ocorrer como resultado do uso de um pacote que apresenta o problema (2), mas, fora isso, não estou convencido de que (1) seja fácil de encontrar. Eu gostaria de ver um caso de uso do mundo real que demonstra o problema para ver como alguém configurou seu bundler, mas aqui está uma lista das maneiras que eu sei que você pode fazer isso (até agora):

  1. Importe explicitamente de 'three/src/Three.js' ou 'three/build/three.min.js' (o que não é recomendado nos documentos).
  2. Reconfigure seu bundler para usar o campo package.main vez do campo package.module ao resolver. Os três grandes bundlers Rollup , Webpack e Parcel preferem module vez de main por padrão, entretanto. Parece que esse caso de uso seria incomum, mas isso é apenas uma suposição.
  3. Use npm link para incluir um pacote com link simbólico que depende de três (isso é corrigido usando a opção preserveSymlinks do rollup)
  4. Use três e exemplos em codesandbox.io porque a plataforma prioriza o campo principal em vez do módulo .

O número 4 parece ser o único que poderia ser encontrado facilmente, embora eu saiba que as pessoas estão fazendo 1 para sacudir uma árvore. Os outros sentem que estão fora de nosso controle ou seriam muito incomuns.

@chabb

pelo que entendi, acho que é porque os exemplos estão gerando import from "../../../build/three.module.js"; ...

Este não é o caso, leia o que expliquei aqui: https://github.com/mrdoob/three.js/issues/17482#issuecomment -583694493. /^three funciona porque corresponde à string 'three/examples/jsm/controls/OrbitControls.js' que também deve ser externa porque faz parte da biblioteca three.js, enquanto a string 'three' não. O mesmo pode acontecer com outras dependências também. Eu recomendo usar regex para todas as dependências para evitar outras armadilhas desconhecidas ou comparar com qualquer pacote com um especificador de módulo vazio.

@gkjohnson Obrigado pela explicação detalhada, isso faz sentido para mim.

Parece que isso não resolve o problema neste tópico, mas como já mencionei isso algumas vezes no tópico, finalmente testei um polyfill de mapa de importação: https://github.com/KhronosGroup/ KTX-Software / pull / 172 / files. Com esse polyfill, import * as THREE from 'three'; funciona no navegador da web.

Se o navegador mostrasse alguma confiança ...
https://github.com/WICG/import-maps/issues/212#issuecomment -663564421

Encontrei o mesmo problema ao adicionar uma subclasse de passagem a um dos meus projetos

import { /* stuff */ } from 'three'
import { Pass } from 'three/examples/jsm/postprocessing/Pass.js'

E como eu preferia copiar o código de acesso em meu módulo, para não ter que importá-lo mais tarde de three.js no navegador, fui em frente e encontrei uma solução alternativa:

const threeModulePath = path.resolve( __dirname, 'node_modules/three/build/three.module.js' );

export default {
    /* ..... */
    external: [ 'three' ],
    output: [
        {
            /* .... */
            globals : {
                'three': 'THREE',
                [ threeModulePath ]: 'THREE',
            }
        }
    ]
};

Dessa forma, funciona com navegadores e as importações de módulo também devem funcionar.

Editar :

Carregar de um projeto três local (veja o exemplo abaixo) interromperá essa abordagem e exigirá alguma solução alternativa adicional.

"dependencies" : {
    "three": "file:../three.js"
}

Bem, eu fui em frente e fiz uma nova versão que suporta link local:

const threeName = "three"; // Change with your three package name
const dependencies = require('./package.json').dependencies;
const splits = dependencies[threeName].split('file:');

const modulePath = (splits.length > 1) ?
    path.resolve(__dirname, splits[1], 'build/three.module.js'):                  // Resolve local path
    path.resolve(__dirname, 'node_modules', threeName, 'build/three.module.js');  // Resolve node_module path

const external = [
    threeName,
    modulePath,
]

const globals = {
    [threeName]: 'THREE',
    [modulePath]: 'THREE',
}

@Mcgode Isso foi abordado acima em https://github.com/mrdoob/three.js/issues/17482#issuecomment -530957570. Se você estiver usando Rollup e quiser marcar three.js como externo ao usar módulos de exemplo, faça o seguinte, conforme sugerido:

externals: p => /^three/.test(p),

Não há razão para tornar a configuração tão complicada. Isso garantirá que o arquivo Pass.js e o módulo three.js sejam marcados como externos.

@gkjohnson Meu caso de uso não é exatamente o mesmo, já que quero apenas three lib marcado como externo, não o exemplo (quero que o exemplo seja empacotado com minha construção).

Estou construindo uma biblioteca com três como externo, quero que o exemplo seja agrupado ao longo da construção, mas sem três, e como discutido acima, ao importar o módulo de exemplos, a saída conterá o código de três. É possível conseguir com o webpack?

import {  } from "three";
import { Line2 } from "three/examples/jsm/lines/Line2";
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry";

@Mcgode @recardinal Não acho que seja possível. Eu queria fazer o mesmo, então apenas copiei / colei o código dos exemplos; no meu caso tive que 'ajustar' as importações e exportações e pronto. Obviamente, isso não é ideal, mas era bom o suficiente para o meu caso de uso.

Eu tenho um caso de uso semelhante aqui com Webpack e THREE como externo. As seguintes importações fazem com que three.module.js seja incluído na saída agrupada.

import * as THREE from 'three';
import { ColladaLoader } from 'three/examples/jsm/loaders/ColladaLoader';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';

Eu li em algum lugar que example / js / * será removido em algum ponto. Seria bom se os exemplos jsm "simplesmente funcionassem" antes disso.

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

Questões relacionadas

qornflex picture qornflex  ·  113Comentários

arefin86 picture arefin86  ·  64Comentários

fernandojsg picture fernandojsg  ·  85Comentários

mrdoob picture mrdoob  ·  75Comentários

arctwelve picture arctwelve  ·  92Comentários