Three.js: L'importation d'exemples de modules jsm amène les bundlers à regrouper deux fois le code source three.js

Créé le 12 sept. 2019  ·  43Commentaires  ·  Source: mrdoob/three.js

L'importation à partir de three/examples/jsm/.../<module> amène les bundlers (testés avec le cumul) à inclure la bibliothèque deux fois (ou plusieurs fois).

Par exemple, lors de l'exécution de import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' , le bundler suivra l'importation et dans OrbitControls.js, les importations proviennent de ../../../build/three.module.js . Cependant, il n'y a aucun moyen pour le bundler (externe) de savoir que ../../../build/three.module.js est le même module que three .

Une solution pour cela serait de traiter les exemples de modules comme des packages externes et d'importer à partir de three au lieu de ../../../build/three.module.js . Cela pourrait casser la configuration de rollup de three.js, mais il devrait être possible de dire à rollup que three est un alias pour le point d'entrée principal de trois ( src/Three.js ).

Commentaire le plus utile

Je pense que c'est juste quelque chose à quoi s'habituer. Maintenant que je pense que j'ai compris, je suis d'accord avec la façon dont c'est.

BTW, j'ai mis à jour trois jsfundamentals pour qu'ils soient tous basés sur esm, donc 🤞

Tous les 43 commentaires

(testé avec rollup)

Je ne peux pas le confirmer avec le rollup. Si vous le faites comme dans la configuration de projet suivante, tout fonctionne comme prévu.

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

Si vous traitez three comme une dépendance externe :

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

alors la sortie ne doit pas contenir le code source de three.js, mais elle inclut tout.

Si, toutefois, vous n'importez pas les OrbitControls, la sortie n'inclura que le code source du fichier main.js .

vous pouvez l'essayer en commentant l' import OrbitControls , puis en 'three' comme dépendance externe).

Ceci est lié à #17220 -- l'une des solutions proposées était de remplacer le champ main dans package.json par le chemin de construction du module mais cela ne résoudrait pas ce cas d'utilisation.

Juste pour être clair, le problème ici est que si three est marqué comme externe pour créer un package séparé qui dépend de trois dans la configuration de cumul qui n'attrape pas la référence matérielle à ../../../build/three.module.js et l'inclut dans la construction. Par exemple, la construction du fichier suivant inclura par inadvertance le code OrbitControls _et_ le code threejs dans le bundle, ainsi qu'une autre copie de trois lorsqu'il sera construit avec la configuration publiée 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, il peut être intéressant de noter que même si le chemin dans OrbitControls.js est modifié en three OrbitControls sera toujours inclus dans votre bundle, ce qui peut être souhaité ou non et pourrait entraîner au moins le code OrbitControls étant inclus deux fois dans les applications dépendantes.

Je ne veux pas proposer cela comme une solution à long terme ou la meilleure, mais changer la configuration pour marquer OrbitControls (et tous les fichiers dans les trois dossiers) comme externe résoudrait cela dans les deux cas :

export default {
    // ...

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

    // ...
};

Je ne veux pas proposer cela comme une solution à long terme ou la meilleure, mais changer la configuration pour marquer OrbitControls (et tous les fichiers des trois dossiers) comme externes résoudrait cela dans les deux cas :

Pour une raison quelconque, je m'attendais à ce que le cumul traite également 'three/examples/jsm/controls/OrbitControls.js' comme externe par défaut. La solution que vous proposez est donc bonne pour mon cas d'utilisation.

Le #17220 connexe est très pertinent. La conversation devrait probablement se poursuivre là-bas.

Alors que se passe-t-il si vous faites cela ?

// 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);

Cela fonctionnerait, mais ce n'est pas faisable, car toute autre bibliothèque ou morceau de code dépendant de trois importera à partir de "trois", puis il se casse à nouveau. Package.json indique normalement à l'environnement comment résoudre, "build/three.module" est un détail de distribution qui ne devrait pas fuir. Lorsque la résolution est ignorée, cela ne fait qu'inviter des problèmes d'espace de noms.

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

@gkjohnson Et si l'utilisateur souhaite inclure l'instance "trois" et OrbitControls dans le bundle ?

Pas sûr que ce soit lié, une chose similaire se produit si vous essayez d'utiliser des modules en direct comme celui-ci

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';

charge trois.js deux fois, une fois à partir du CDN et à nouveau à partir de threejs.org

Ce n'est peut-être pas la façon dont les modules sont censés être utilisés avec trois, mais à partir du pré 106, il y a des milliers de sites et d'exemples qui le font

<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>

Tous les exemples montrent l'utilisation de modules en direct au lieu de la construction (bundling), donc dans un sens, ils ne montrent pas la manière réelle d'utiliser three.js comme ils le faisaient auparavant. En d'autres termes, les anciens exemples fonctionnaient hors de la boîte. Les nouveaux exemples ne le font pas. Pour qu'un exemple fonctionne, vous devez extraire le JavaScript de l'exemple et le mettre dans un fichier .js séparé, puis mettre three.js localement (probablement via npm). Corrigez tous les chemins dans les exemples afin qu'ils soient des chemins basés sur les packages (pas de ../.././build), et enfin utilisez le rollup

C'est un assez gros changement par rapport aux versions sans module pour lesquelles il suffisait de changer les chemins

@mrdoob

Avec la configuration originale de @adrian-delgado, three.js sera inclus une fois et les contrôles d'orbite seront inclus une fois et aucun package ne sera marqué comme externe. Avec la configuration que j'ai proposée, il y aura une dépendance externe sur three/build/three.module.js et three/examples/jsm/controls/OrbitControls.js dans le bundle produit.

@EliasHasle

Que se passe-t-il si l'utilisateur souhaite inclure l'instance « trois » et OrbitControls dans le bundle ?

Ensuite, le champ external doit être exclu, auquel cas une seule copie de trois commandes d'orbite sera incluse dans le bundle. rollup-plugin-node-resolve (nécessaire au rollup pour prendre en charge la résolution du module et utilisé dans les configurations ci-dessus) utilise par défaut le champ module de package.json (voir l'option mainFields ) donc l'orbite contrôles trois référence et "trois" se résoudra au même script. _Si mainFields est changé en ["main", "module"] donc "main" est utilisé au lieu de "module" dans package.json_ alors deux copies sur trois seront incluses ici et les choses se briseront de la manière qui a été mentionné précédemment. Cependant, cela nécessite de changer ce champ. Si "main" est utilisé, cependant, rollup-plugin-commonjs devra probablement être également nécessaire, car rollup ne sait pas comment traiter les fichiers commonjs qui utilisent require par défaut.

@greggman

Malheureusement, je ne pense pas qu'un remplacement naïf de modules fonctionnera si facilement dans ce cas. Aucune des solutions proposées ne traitera ce cas et je ne pense pas qu'il y ait quoi que ce soit d'officiel pour le moment qui puisse être utilisé pour aider dans le cas de l'importation du script de base et de l'exemple à partir d'hôtes distincts. Les cartes d'importation sont la seule chose en cours pour aider avec cela, pour autant que je sache. Si l'exemple et les trois sont importés du même hôte, alors une seule copie de trois sera chargée :

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';

Selon le cas d'utilisation, il est peut-être préférable de continuer à utiliser les balises de script classiques ?

@greggman

Pas sûr que ce soit lié, une chose similaire se produit si vous essayez d'utiliser des modules en direct comme celui-ci

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';

Ouais... N'utilisez pas de modules comme ça

Ouais... N'utilisez pas de modules comme ça

D'accord. On peut soutenir que les documents et les exemples ciblent principalement les développeurs inexpérimentés et le fait que les exemples jsm sont la valeur par défaut et qu'aucun d'entre eux ne fonctionnera sans constructeur ni via un CDN est une sorte de grand changement.

Auparavant, vous pouviez essentiellement afficher la source sur un exemple, copier et coller dans jsfiddle/codepen, etc., corriger les chemins dans les balises de script et cela s'exécuterait. Maintenant, tous les exemples ne fonctionneront pas à moins que vous ne vous connectiez directement au site three.js et que vous les regardiez casser chaque fois que la version est modifiée. (oui, je sais que les exemples sans module existent mais ce ne sont pas ceux qui sont liés à partir de 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';

Ne fonctionne pas, les OrbitControls ne sont pas sur le CDN et les chemins à l'intérieur des OrbitContrls ../../../bulild/three.js ne sont pas le bon chemin pour le faire fonctionner

// ou

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

Ne fonctionne pas non plus car il se brisera à chaque fois que three.js pousse une nouvelle version

Peut-être pousser le dossier examples/js vers un CDN et trois tels que la simple correction des URL dans l'exemple de code fonctionnera toujours? Cela signifie que three.module.js doit être à

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

build ajouté au chemin

Pour mentionner les options, d'autres CDN comme jsdelivr ou unpkg prennent en charge les modules ES :

Auparavant, vous pouviez essentiellement afficher la source sur un exemple, copier et coller dans jsfiddle/codepen, etc., corriger les chemins dans les balises de script et cela s'exécuterait ...

Je pense que nous aurons besoin de cartes d'importation pour faire quelque chose d'utile à ce sujet, pour le meilleur ou pour le pire.

Maintenant, bien que tous les exemples ne s'exécutent que si vous vous connectez directement au site three.js

Je n'encouragerais vraiment personne à créer un lien direct vers des scripts en direct sur le site threejs... ce ne sera jamais une bonne idée. Il existe des alternatives versionnées, par commentaire ci-dessus.

La documentation qui, idéalement, répondrait à ces questions est la page Importer via les modules . Y a-t-il des cas que nous devrions couvrir là-bas? Je suppose que mentionner les CDN serait une bonne idée.

Mentionner les CDN serait une bonne idée. Mentionnant également que le CDN cloudflare, le premier hit, sur Google n'est pas bon pour les modules (à moins que cela ne change)

@greggman

Auparavant, vous pouviez essentiellement afficher la source sur un exemple, copier et coller dans jsfiddle/codepen, etc., corriger les chemins dans les balises de script et cela s'exécuterait.

Je suis de ton côté. Le pire des modules est que vous ne pouvez plus accéder à camera ou renderer depuis la console dans les exemples 😟

Et si on commençait à utiliser unpkg ?

Voulez-vous dire commencer à l'utiliser dans la documentation comme la page Importer via des modules , ou l'utiliser dans le projet d'une manière ou d'une autre ?

Le pire des modules est que vous ne pouvez plus accéder à la caméra ou au moteur de rendu depuis la console dans les exemples

Ouais, c'est frustrant. J'ai jeté ceci (ou similaire) dans les exemples lors du développement local :

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

Je suppose que c'est quelque chose que nous espérons résoudre avec une extension d'outils de développement ?

Une idée qui demanderait quelques recherches, mais qui pourrait être intéressante... si nous serions disposés à ajouter un polyfill de carte d'importation à tous les exemples, je pense que nous pourrions rendre les importations utilisées là-bas 100% compatibles avec npm- et les workflows basés sur les bundles. Par exemple:

<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>

Et si on commençait à utiliser unpkg ?

Voulez-vous dire commencer à l'utiliser dans la documentation comme la page Importer via des modules, ou l'utiliser dans le projet d'une manière ou d'une autre ?

Au lieu de pointer vers https://threejs.org/build/. Actuellement, nous utilisons ce lien dans ISSUE_TEMPLATE .

Et @greggman pourrait probablement passer de https://cdnjs.cloudflare.com/ajax/libs/three.js/108/ à https://unpkg.com/[email protected]/ ?

On dirait que unpkg résout les problèmes dont nous discutons ici.

Ouais, c'est frustrant. J'ai jeté ceci (ou similaire) dans les exemples lors du développement local :

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

Pouah! haha

Je suppose que c'est quelque chose que nous espérons résoudre avec une extension d'outils de développement ?

Oui! ??

@greggman

Pas sûr que ce soit lié, une chose similaire se produit si vous essayez d'utiliser des modules en direct comme celui-ci

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';

Ouais... N'utilisez pas de modules comme ça

Alors aujourd'hui, je me suis retrouvé à faire exactement ça... 😅 C'est une mauvaise habitude en effet, mais le problème est que la plupart des choses fonctionnent, mais si quelque chose casse, c'est assez difficile à cerner.

Dans mon cas, j'importais three.module.js de dev et OBJLoader de master . OBJLoader importé three.module.js de master donc le BufferGeometry n'avait pas la nouvelle propriété usage , et WebGLRenderer avait pas rendu le maillage car il n'a pas trouvé usage , tout le reste a fonctionné cependant 😶

C'est assez poilu...

Je pense que c'est juste quelque chose à quoi s'habituer. Maintenant que je pense que j'ai compris, je suis d'accord avec la façon dont c'est.

BTW, j'ai mis à jour trois jsfundamentals pour qu'ils soient tous basés sur esm, donc 🤞

Il semble que ce soit bien d'avoir un three.module.min.js (ou est-ce que c'est three.min.module.js 😜)

+1

Je viens d'importer trois contrôles d'orbite en tant que modules ES6 et parce que (il semble) les contrôles d'orbite font référence à trois dans le dossier de construction, il m'a fallu un certain temps pour comprendre mes chemins

Super fan, nous pouvons en utiliser trois comme modules, mais ce serait bien d'avoir plus de flexibilité à ce sujet, je ne vais pas entrer dans le fichier de contrôles d'orbite et commencer à déconner, en supposant que ce soit le cas avec d'autres modules également.

Aussi +1 pour un module.js de trois.min. 😎

passant de # 18239, je me suis pris dans un problème similaire en faisant npm link sur un autre paquet qui utilise Three.js.

J'ai développé un plugin three-minifier qui peut aider à résoudre ce problème.

Je suis confronté au même problème. J'écris un composant React à l'aide de three.js et j'importe certains modules à partir des exemples. Une fois qu'il est fourni avec le rollup, si je regarde le bundle, je peux voir qu'il y a une déclaration d'importation pour trois, puis le code Three.js.

Si j'utilise cette instruction d'importation dans mon composant : import * as THREE from "three/build/three.module"
les choses fonctionnent correctement mais Three est alors intégré dans le bundle, ce que je ne veux pas.
J'aimerais avoir une déclaration d'importation pour trois. Si j'utilise import * as THREE from "three , le bundle en aura trois importés en tant que module, mais dès que j'utilise l'un des exemples, alors three.js est ajouté dans le bundle ( = j'ai une déclaration d'importation pour trois, puis le code de trois ), ce qui fait finalement casser mon code

@chabb

J'écris un composant React à l'aide de three.js et j'importe certains modules à partir des exemples. Une fois qu'il est fourni avec le rollup, si je regarde le bundle, je peux voir qu'il y a une déclaration d'importation pour trois, puis le code Three.js.

La solution publiée ici devrait résoudre votre problème : https://github.com/mrdoob/three.js/issues/17482#issuecomment -530957570.

Je pense que beaucoup de ces problèmes proviennent de personnes qui ne comprennent pas complètement ce qui se passe avec leur bundler (ce qui est compréhensible), mais ces problèmes ne sont pas uniques à trois. Il est possible, cependant, qu'une double importation accidentelle de trois cœurs soit juste plus perceptible qu'avec d'autres bibliothèques. Regrouper une dépendance qui est destinée à être externe comme lodash, un composant de réaction ou OrbitControls peut simplement être plus facilement manqué.

En ce qui concerne le fait de dépendre d'un package externe, Rollup documente ce comportement et fournit une option ici et Webpack a une option similaire ici . Dans ce cas, si les fichiers d'exemple faisaient plutôt référence à "trois", alors que la bibliothèque principale ne serait pas regroupée, vous obtiendriez toujours des groupes d'exemples de code en double, ce qui est son propre problème. Et je ne pense pas que ce projet puisse faire quoi que ce soit pour aider un bundler à interpréter les pièges des liens npm. Je pense que le seul cas problématique que j'ai vu et qui, selon moi, n'est pas le résultat d'un bundler mal configuré est le cas codesandbox.

Pour les cas de bundler, la réponse est peut-être de documenter, d'ajouter un guide de dépannage ou un lien vers la façon de configurer les bundlers communs sur la page d'importation via des modules .

J'ai l'intuition que si les packages examples/jsm pouvaient changer ce modèle...

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

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

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

... ces problèmes seraient beaucoup plus faciles à résoudre. Malheureusement, je ne sais pas comment nous gérerions les exemples HTML sur le site Web de threejs sans une configuration de construction complexe à ce moment-là. Un polyfill de carte d'importation sur le site Web de threejs pourrait le résoudre, mais je ne suis pas sûr. :/

si les fichiers d'exemple faisaient plutôt référence à "trois", alors que la bibliothèque principale ne serait pas regroupée, vous obtiendriez toujours des groupes d'exemples de code en double...

Je ne suis pas tout à fait ça. Parce qu'il s'agit d'importations de chemin relatif ? Nous pourrions les rendre relatifs au package.

@donmccurdy

J'ai l'intuition que si les packages exemples/jsm pouvaient changer ce modèle... ces problèmes seraient beaucoup plus faciles à résoudre.

Je pense que cela donnerait l'impression que cela serait résolu, mais les gens auraient toujours du code dupliqué qui est juste plus difficile à remarquer car cela ne provoque pas la rupture de l'application.

Je ne suis pas tout à fait ça. Parce qu'il s'agit d'importations de chemin relatif ? Nous pourrions les rendre relatifs au package.

Désolé si je ne suis pas clair, je pense que c'est un peu difficile à expliquer - j'espère que c'est un peu plus clair. Je vais utiliser le cas Rollup :

Dans les cas ci-dessus où les gens veulent cumuler un package avec three marqué comme externe, je suppose qu'ils construisent une bibliothèque où three.js serait une dépendance de pair sur laquelle une autre application pourrait s'appuyer :

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...

Ici, l'objectif serait que les importations three.js ci-dessus restent dans la bibliothèque et que le bundle charge trois et OrbitControls en tant que dépendances homologues, donc si l'application utilise également three.js et OrbitControls, vous n'importez pas non plus deux fois.

Les gens s'attendent à ce que l'option external: [ 'three' ] réalise ce comportement pour eux (je l'ai certainement fait), mais ce n'est pas le cas car la chaîne ne correspond pas au chemin d'importation OrbitControls. Cela a pour résultat que OrbitControls est involontairement groupé et donc ../../../build/three.module.js également (car il ne correspond pas non plus à la chaîne). Je pense que les gens indiquent que le fichier de base three.js est regroupé parce qu'il est beaucoup plus visible - les applications se cassent, le groupe de bibliothèques est beaucoup plus volumineux, etc. first place._ La façon correcte de configurer Rollup ici est de définir l'option sur external: path => /^three/.test( path ) .

Ce n'est pas unique à trois. Rollup utilise lodash comme exemple dans ses documents, mais il sera difficile / impossible de remarquer si 'lodash/merge' est inclus dans le code de votre bibliothèque car il est si petit et ne provoquera pas de bogues d'importation en double. Material UI encourage les références de fichiers imbriqués dans les importations et de même, le paramètre external: ['@material-ui/core'] ne parviendrait pas à exclure '@material-ui/core/Button' du bundle.

Je ne pense pas qu'il soit utile de modifier l'exemple de code pour ces cas d'utilisation, car cela entraînera toujours un code en double qui ne serait pas là si le bundler était correctement configuré.

Deux cas ici :

(1) l'utilisateur veut trois js et des exemples inclus une fois, obtient quelque chose deux fois

Par exemple, lors de la création d'une application.

(2) l'utilisateur veut trois js et des exemples inclus zéro fois, obtient quelque chose 1+ fois

Par exemple, lors de la construction d'une bibliothèque avec trois comme dépendance externe ou par les pairs.


Pour autant que je sache, (1) et (2) sont toujours des problèmes faciles à résoudre ? Si l'approche ci-dessus résout (1), cela seul est utile. Je ne suis pas sûr de (2). Peut-être que l'astuce /^three/.test( path ) devrait être mentionnée lors de l' import via les modules ?

@gkjohnson Merci pour cette explication, cela m'a vraiment aidé à clarifier mes pensées

Dans ma configuration de cumul, je définissais le external cette façon

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

Je pensais que cela fonctionnerait, car trois seraient traités comme des dépendances externes; mais comme vous l'avez mentionné, vous devez utiliser une expression régulière (pour autant que je sache, je suppose que c'est parce que les exemples font
import from "../../../build/three.module.js"; ). Alors j'ai fini par faire

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

C'est une question un peu sans rapport, mais je m'attendrais à ce que toutes les dépendances que j'ai déclarées dans package.json ne fassent pas partie du bundle ? Est-ce une hypothèse correcte ?

@donmccurdy

Pour autant que je sache, (1) et (2) sont toujours des problèmes faciles à résoudre ?

À mon avis, (2) est le résultat d'une configuration incorrecte du bundler et nous pouvons peut-être y remédier en mettant à jour la documentation avec quelques suggestions pour les bundlers. (1) peut survenir à la suite de l'utilisation d'un package qui souffre d'un problème (2), mais à part cela, je ne suis pas convaincu que (1) est facile à trouver. J'aimerais voir un cas d'utilisation réel qui illustre le problème pour voir comment quelqu'un a configuré son bundler, mais voici une liste des façons dont je sais que vous pouvez atteindre ceci (jusqu'à présent):

  1. Importez explicitement depuis 'three/src/Three.js' , ou 'three/build/three.min.js' (ce qui n'est pas recommandé dans la doc).
  2. Reconfigurez votre bundler pour utiliser le champ package.main plutôt que le champ package.module lors de la résolution. Les trois grands fardeleuses Rollup , webpack et colis tous préfèrent module sur main par défaut, cependant. Ce cas d'utilisation semble être rare, mais ce n'est qu'une hypothèse.
  3. Utilisez npm link pour inclure un package lié symboliquement qui dépend de trois (ceci est corrigé en utilisant l'option preserveSymlinks du rollup)
  4. Utilisez trois et des exemples dans codesandbox.io car la plate-forme donne la priorité

Le numéro 4 semble être le seul sur lequel on puisse tomber facilement, même si je sais que les gens font 1 pour secouer les arbres. Les autres ont l'impression qu'ils sont hors de notre contrôle ou qu'ils seraient très rares.

@chabb

pour autant que je sache, je suppose que c'est parce que les exemples font import from "../../../build/three.module.js"; ...

Ce n'est pas le cas, veuillez lire ce que j'ai expliqué ici : https://github.com/mrdoob/three.js/issues/17482#issuecomment -583694493. /^three fonctionne car il correspond à la chaîne 'three/examples/jsm/controls/OrbitControls.js' qui devrait également être externe car elle fait partie de la bibliothèque three.js alors que la chaîne 'three' ne le fait pas. La même chose peut arriver avec d'autres dépendances. Je recommanderais d'utiliser regex pour toutes les dépendances afin d'éviter d'autres pièges inconnus ou de faire correspondre n'importe quel package avec un spécificateur de module nu.

@gkjohnson Merci pour l'explication détaillée, cela a du sens pour moi.

Il semble que cela ne résolve pas le problème dans ce fil après tout, mais comme je l'ai déjà mentionné plusieurs fois dans le fil, j'ai finalement testé un polyfill de carte d'importation : https://github.com/KhronosGroup/ KTX-Software/pull/172/fichiers. Avec ce polyfill, import * as THREE from 'three'; fonctionne dans le navigateur Web.

Si seulement le navigateur montrait une certaine confiance...
https://github.com/WICG/import-maps/issues/212#issuecomment-663564421

J'ai rencontré le même problème lors de l'ajout d'une sous-classe pass à l'un de mes projets

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

Et comme j'ai préféré copier le code Pass dans mon module, afin de ne pas avoir à l'importer plus tard depuis three.js sur navigateur, j'ai trouvé une solution de contournement :

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

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

De cette façon, cela fonctionne avec les navigateurs et les importations de modules devraient également fonctionner.

Modifier :

Le chargement à partir d'un projet local à trois (voir l'exemple ci-dessous) interrompra cette approche et nécessitera une solution de contournement supplémentaire.

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

Eh bien, je suis allé de l'avant et j'ai créé une nouvelle version qui prend en charge le lien 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 Cela a été abordé ci-dessus dans https://github.com/mrdoob/three.js/issues/17482#issuecomment -530957570. Si vous utilisez Rollup et que vous souhaitez marquer three.js comme externe lorsque vous utilisez des exemples de modules, vous devez procéder comme suit :

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

Il n'y a aucune raison de rendre la configuration si compliquée. Cela garantira que le fichier Pass.js et le module three.js sont marqués comme externel.

@gkjohnson Mon cas d'utilisation n'est pas exactement le même, car je veux seulement que la three soit marquée comme externe, pas l'exemple (je veux que l'exemple soit fourni avec ma version).

Je construis une bibliothèque avec trois en tant qu'externe, je veux que l'exemple soit regroupé à la largeur de la construction mais sans trois, et comme indiqué ci-dessus, lors de l'importation de module à partir d'exemples, la sortie contiendra le code de trois. Est-ce possible de réaliser avec webpack ?

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

@Mcgode @recardinal Je ne pense pas que ce soit possible. Je voulais faire la même chose alors j'ai juste copié/collé le code des exemples ; dans mon cas, j'ai dû « ajuster » les importations et les exportations et c'était tout. Évidemment, ce n'est pas idéal mais c'était assez bon pour mon cas d'utilisation.

J'ai un cas d'utilisation similaire ici avec Webpack et THREE en tant qu'externe. Les importations suivantes entraînent l'inclusion de three.module.js dans la sortie groupée.

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';

J'ai lu quelque part que examples/js/* sera supprimé à un moment donné. Ce serait bien si les exemples jsm "fonctionnent" avant cela.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

scrubs picture scrubs  ·  3Commentaires

yqrashawn picture yqrashawn  ·  3Commentaires

ghost picture ghost  ·  3Commentaires

danieljack picture danieljack  ·  3Commentaires

Horray picture Horray  ·  3Commentaires