Three.js: Das Importieren von Beispiel-jsm-Modulen führt dazu, dass Bundler den drei.js-Quellcode zweimal bündeln

Erstellt am 12. Sept. 2019  ·  43Kommentare  ·  Quelle: mrdoob/three.js

Der Import aus three/examples/jsm/.../<module> führt dazu, dass Bundler (mit Rollup getestet) die Bibliothek zweimal (oder mehrmals) einschließen.

Wenn Sie beispielsweise import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' ausführen, folgt der Bundler dem Import und in OrbitControls.js kommen die Importe von ../../../build/three.module.js . Es gibt jedoch keine Möglichkeit für den (externen) Bundler zu wissen, dass ../../../build/three.module.js dasselbe Modul wie three .

Eine Lösung hierfür wäre, die Beispielmodule als externe Pakete zu behandeln und von three anstelle von ../../../build/three.module.js importieren. Dies könnte die Rollup-Konfiguration von Three.js zerstören, aber es sollte möglich sein, Rollup mitzuteilen, dass three ein Alias ​​für den Haupteinstiegspunkt von drei ist ( src/Three.js ).

Hilfreichster Kommentar

Ich denke, es ist einfach gewöhnungsbedürftig. Jetzt, wo ich denke, dass ich es verstanden habe, bin ich damit einverstanden, wie es ist.

Übrigens, ich habe Threejsfundamentals so aktualisiert, dass alle auf Esm basieren, also

Alle 43 Kommentare

(getestet mit Rollup)

Das kann ich mit Rollup nicht bestätigen. Wenn Sie es wie im folgenden Projekt-Setup machen, funktioniert alles wie erwartet.

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

Wenn Sie three als externe Abhängigkeit behandeln:

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

dann sollte die Ausgabe nicht den Quellcode von Three.js enthalten, aber alles.

Wenn Sie die OrbitControls jedoch nicht importieren, enthält die Ausgabe nur den Quellcode der Datei main.js .

Sie können es ausprobieren, indem Sie den OrbitControls-Import auskommentieren und dann erneut 'three' als externe Abhängigkeit).

Dies hängt mit #17220 zusammen – eine der dort vorgeschlagenen Lösungen bestand darin, das Feld main in package.json durch den Modul-Build-Pfad zu ersetzen, aber das würde diesen Anwendungsfall nicht beheben.

Um es klarzustellen, das Problem hier ist, dass three zwar als extern markiert ist, um ein separates Paket zu erstellen, das von drei in der Rollup-Konfiguration abhängig ist, die den harten Verweis auf ../../../build/three.module.js nicht abfängt und schließt es in den Build ein. Wenn Sie beispielsweise die folgende Datei erstellen, wird versehentlich der OrbitControls-Code _und_ der Threejs-Code in das Bundle aufgenommen, sowie eine weitere Kopie von drei importiert, wenn sie mit der von @adrian-delgado veröffentlichten Konfiguration erstellt wird.

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

console.log(THREE, OrbitControls);

@adrian-delgado Es ist vielleicht erwähnenswert, dass OrbitControls auch dann in Ihrem Bundle enthalten ist, wenn der Pfad in OrbitControls.js in three geändert wird, was möglicherweise gewünscht oder nicht erwünscht ist und zumindest zu führen könnte der OrbitControls-Code wird zweimal in abhängige Anwendungen eingefügt.

Ich möchte dies nicht als langfristige oder beste Lösung vorschlagen, aber das Ändern der Konfiguration, um OrbitControls (und alle Dateien in den drei Ordnern) als extern zu markieren, würde dies in beiden Fällen lösen:

export default {
    // ...

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

    // ...
};

Ich möchte dies nicht als langfristige oder beste Lösung vorschlagen, aber das Ändern der Konfiguration, um OrbitControls (und alle Dateien in den drei Ordnern) als extern zu markieren, würde dies in beiden Fällen lösen:

Aus irgendeinem Grund habe ich erwartet, dass Rollup 'three/examples/jsm/controls/OrbitControls.js' standardmäßig auch als extern behandelt. Ihre vorgeschlagene Lösung ist also gut für meinen Anwendungsfall.

Die zugehörige #17220 ist sehr relevant. Dort sollte das Gespräch wohl fortgesetzt werden.

Was passiert also, wenn Sie dies tun?

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

Es würde funktionieren, aber es ist nicht machbar, weil jede andere Bibliothek oder jedes andere Codestück, das von drei abhängig ist, von "drei" importiert wird und dann wieder bricht. Package.json teilt der Umgebung normalerweise mit, wie es aufzulösen ist, "build/three.module" ist ein Verteilungsdetail, das nicht durchsickern sollte. Wenn die Auflösung übersprungen wird, führt dies nur zu Namespace-Problemen.

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

@gkjohnson Was ist, wenn der Benutzer die "drei" Instanz und OrbitControls in das Bundle aufnehmen möchte?

Ich bin mir nicht sicher, ob es damit zusammenhängt. Ähnliches passiert, wenn Sie versuchen, Module so live zu verwenden

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

lädt drei.js zweimal, einmal vom CDN und noch einmal von threejs.org

Vielleicht ist das nicht die Art und Weise, wie Module mit drei verwendet werden sollen, aber gerade von vor 106 aus gibt es Tausende von Websites und Beispielen, die dies tun

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

Alle Beispiele zeigen, dass Module live verwendet werden, anstatt sie zu bauen (bündeln), so dass sie in gewisser Weise nicht die tatsächliche Verwendung von Three.js wie früher zeigen. Mit anderen Worten, die alten Beispiele funktionierten out of the box. Die neuen Beispiele sind nicht AFAIK. Damit ein Beispiel funktioniert, müssen Sie das JavaScript aus dem Beispiel extrahieren und in eine separate .js-Datei einfügen und dann drei.js lokal einfügen (wahrscheinlich über npm). Korrigieren Sie alle Pfade in den Beispielen, sodass es sich um paketbasierte Pfade handelt (kein ../.././build) und verwenden Sie schließlich Rollup

Das ist eine ziemlich große Änderung gegenüber den Nicht-Modul-Versionen, für die nur das Ändern der Pfade ausreichte

@mrdoob

Bei der ursprünglichen Konfiguration von @adrian-delgado werden drei.js einmal und Orbit Controls einmal eingeschlossen und keine Pakete werden als extern markiert. Mit der von mir vorgeschlagenen Konfiguration wird es eine externe Abhängigkeit von three/build/three.module.js und three/examples/jsm/controls/OrbitControls.js im produzierten Bundle geben.

@EliasHasle

Was ist, wenn der Benutzer die "drei" Instanz und OrbitControls in das Bundle aufnehmen möchte?

Dann sollte das Feld external ausgeschlossen werden. In diesem Fall wird eine einzelne Kopie von drei und Orbit-Steuerelementen in das Paket aufgenommen. rollup-plugin-node-resolve (wird für Rollup benötigt, um die Modulauflösung zu unterstützen und wird in den obigen Konfigurationen verwendet) verwendet standardmäßig das Modulfeld von package.json (siehe die Option mainFields ), so dass der Orbit steuert drei Verweise und "drei" wird in dasselbe Skript aufgelöst. _Wenn mainFields in ["main", "module"] geändert wird, also "main" anstelle von "module" in package.json_ verwendet wird, dann werden zwei Kopien von drei hier eingefügt und die Dinge werden auf die Art und Weise brechen, wie es bisher war zuvor erwähnt. Allerdings muss dieses Feld geändert werden. Wenn jedoch "main" verwendet wird, wird wahrscheinlich auch rollup-plugin-commonjs benötigt, da rollup nicht weiß, wie Commonjs-Dateien verarbeitet werden, die standardmäßig erfordern.

@greggman

Leider glaube ich nicht, dass ein naiver Austausch von Modulen in diesem Fall so einfach funktioniert. Keine der vorgeschlagenen Lösungen wird diesen Fall behandeln und ich glaube nicht, dass es im Moment etwas Offizielles gibt, das verwendet werden kann, um den Fall des Imports des Kernskripts und des Beispiels von separaten Hosts zu unterstützen. Importkarten sind das einzige, was in Arbeit ist, um dabei zu helfen, soweit ich weiß. Wenn sowohl das Beispiel als auch drei von demselben Host importiert werden, wird nur eine einzelne Kopie von drei geladen:

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

Je nach Anwendungsfall ist es vielleicht vorzuziehen, weiterhin die klassischen Skript-Tags zu verwenden?

@greggman

Ich bin mir nicht sicher, ob es damit zusammenhängt. Ähnliches passiert, wenn Sie versuchen, Module so live zu verwenden

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

Ja... Benutze keine Module wie diese 😁

Ja... Benutze keine Module wie diese 😁

Einverstanden. Es ist nur fraglich, ob die Dokumente und Beispiele hauptsächlich auf unerfahrene Entwickler abzielen, und die Tatsache, dass jsm-Beispiele die Standardeinstellung sind und keines von ihnen ohne einen Builder oder über ein CDN funktioniert, ist eine große Änderung.

Früher konnte man im Grunde genommen den Quellcode in einem Beispiel anzeigen, kopieren und in jsfiddle / codepen usw. einfügen, die Pfade in den Skript-Tags korrigieren und es würde laufen. Jetzt werden jedoch alle Beispiele nicht ausgeführt, es sei denn, Sie verlinken direkt auf die Three.js-Site und sehen zu, wie sie jedes Mal unterbrochen werden, wenn die Version gestoßen wird. (Ja, ich weiß, dass es die Nicht-Modul-Beispiele gibt, aber das sind nicht die, auf die von https://threejs.org/examples verlinkt wird)

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

Funktioniert nicht, OrbitControls sind nicht auf dem CDN und die Pfade in den OrbitContrls ../../../bulild/three.js sind nicht der richtige Pfad, damit es funktioniert

// oder

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

Funktioniert auch nicht, da es jedes Mal kaputt geht, wenn Three.js eine neue Version pusht

Vielleicht den Ordner "examples/js" in ein CDN und drei verschieben, damit nur die URLs im Beispielcode repariert werden können? Das bedeutet, dass drei.module.js bei . sein muss

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

build zum Pfad hinzugefügt

Früher konnte man im Grunde genommen den Quellcode in einem Beispiel anzeigen, kopieren und in jsfiddle / codepen usw. einfügen, die Pfade in den Skript-Tags korrigieren und es würde laufen ...

Ich denke, wir werden Importkarten brauchen, um etwas Nützliches zu tun, zum Guten oder zum Schlechten.

Jetzt werden jedoch alle Beispiele nicht ausgeführt, es sei denn, Sie verlinken direkt auf die Three.js-Site

Ich würde wirklich niemanden ermutigen, direkt auf Live-Skripte auf der Threejs-Site zu verlinken ... das wird nie eine gute Idee sein. Es gibt versionierte Alternativen, pro Kommentar oben.

Die Dokumentation, die diese Fragen idealerweise beantwortet, ist die Seite Import über Module . Gibt es Fälle, die wir dort abdecken sollten? Ich denke, es wäre eine gute Idee, die CDNs zu erwähnen.

Es wäre eine gute Idee, die CDNs zu erwähnen. Erwähnen Sie auch, dass das Cloudflare-CDN, der erste Hit bei Google, für Module nicht gut ist (es sei denn, das ändert sich)

@greggman

Früher konnte man im Grunde genommen den Quellcode in einem Beispiel anzeigen, kopieren und in jsfiddle / codepen usw. einfügen, die Pfade in den Skript-Tags korrigieren und es würde laufen.

Ich bin auf deiner Seite. Das Schlimmste an Modulen ist, dass Sie in den Beispielen nicht mehr über die Konsole auf camera oder renderer zugreifen können 😟

Wie wäre es, wenn wir unpkg verwenden?

Meinen Sie damit, es in der Dokumentation wie der Seite Import über Module zu verwenden oder es irgendwie im Projekt zu verwenden?

Das Schlimmste an Modulen ist, dass Sie in den Beispielen nicht mehr von der Konsole aus auf Kamera oder Renderer zugreifen können

Ja, das ist frustrierend. Ich habe dies (oder ähnliches) in die Beispiele geworfen, wenn ich lokal entwickle:

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

Ich gehe davon aus, dass wir das mit einer Dev-Tools-Erweiterung lösen wollen?

Eine Idee, die einige Nachforschungen erfordern würde, aber interessant sein könnte ... wenn wir bereit wären, allen Beispielen ein Import-Map-Polyfill hinzuzufügen, könnten wir die dort verwendeten Importe meiner Meinung nach zu 100% mit npm kompatibel machen. und Bundler-basierte Workflows. Zum Beispiel:

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

Wie wäre es, wenn wir unpkg verwenden?

Meinen Sie damit, es in der Dokumentation wie der Seite Import über Module zu verwenden oder es irgendwie im Projekt zu verwenden?

Anstatt auf https://threejs.org/build/ zu verweisen ISSUE_TEMPLATE .

Und @greggman könnte wahrscheinlich von https://cdnjs.cloudflare.com/ajax/libs/three.js/108/ zu https://unpkg.com/[email protected]/ wechseln?

Scheint nur so, als ob unpkg die Probleme löst, die wir hier besprechen.

Ja, das ist frustrierend. Ich habe dies (oder ähnliches) in die Beispiele geworfen, wenn ich lokal entwickle:

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

Pfui! Haha

Ich gehe davon aus, dass wir das mit einer Dev-Tools-Erweiterung lösen wollen?

Jawohl! 🤞

@greggman

Ich bin mir nicht sicher, ob es damit zusammenhängt. Ähnliches passiert, wenn Sie versuchen, Module so live zu verwenden

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

Ja... Benutze keine Module wie diese 😁

Heute habe ich genau das getan... 😅 Es ist in der Tat eine schlechte Angewohnheit, aber das Problem ist, dass die meisten Dinge funktionieren, aber wenn etwas kaputt geht, ist es ziemlich schwer, es festzunageln.

In meinem Fall importierte ich three.module.js aus dev und OBJLoader aus master . OBJLoader importierte three.module.js aus master sodass BufferGeometry nicht die neue Eigenschaft usage hatte , und WebGLRenderer hatte das Mesh nicht rendern, weil es usage , alles andere hat aber funktioniert

Das ist ziemlich haarig...

Ich denke, es ist einfach gewöhnungsbedürftig. Jetzt, wo ich denke, dass ich es verstanden habe, bin ich damit einverstanden, wie es ist.

Übrigens, ich habe Threejsfundamentals so aktualisiert, dass alle auf Esm basieren, also

Es scheint jedoch gut zu sein, ein three.module.min.js (oder ist das three.min.module.js 😜)

+1

Ich importiere gerade drei & Orbit Controls als ES6 Module & weil (wie es scheint) Orbit Controls sich auf drei im Build-Ordner bezieht, habe ich eine Weile gebraucht, um meine Pfade herauszufinden

Super Fan, wir können drei als Module verwenden, aber es wäre schön, mehr Flexibilität zu haben, ich werde nicht in die Orbit Controls-Datei gehen und anfangen, herumzuspielen, vorausgesetzt, dies ist auch bei anderen Modulen der Fall.

Auch +1 für drei.min.module.js 😎

ein ähnliches Problem darin gefangen , indem Sie sich von # 18239, ich habe npm link auf ein anderes Paket , dass Anwendungen three.js.

Ich habe ein Plugin Drei-Minifier entwickelt, das helfen kann, dieses Problem zu lösen.

Ich stehe vor dem gleichen Problem. Ich schreibe eine React-Komponente mit Three.js und importiere einige Module aus den Beispielen. Sobald es mit Rollup gebündelt ist, kann ich beim Betrachten des Bündels sehen, dass es eine Importanweisung für drei und dann den Three.js-Code gibt.

Wenn ich diese Importanweisung in meiner Komponente verwende: import * as THREE from "three/build/three.module"
die Dinge funktionieren richtig, aber Three ist dann in das Bundle eingebettet, was ich nicht möchte.
Ich hätte gerne eine Importerklärung für drei Personen. Wenn ich import * as THREE from "three , werden im Bundle drei als Modul importiert, aber sobald ich eines der Beispiele verwende, wird drei.js im Bundle hinzugefügt ( = ich habe eine Importanweisung für drei, und dann der Code von drei ), was letztendlich dazu führt, dass mein Code bricht

@chabb

Ich schreibe eine React-Komponente mit Three.js und importiere einige Module aus den Beispielen. Sobald es mit Rollup gebündelt ist, kann ich beim Betrachten des Bündels sehen, dass es eine Importanweisung für drei und dann den Three.js-Code gibt.

Die hier gepostete Lösung sollte Ihr Problem lösen: https://github.com/mrdoob/three.js/issues/17482#issuecomment -530957570.

Ich habe das Gefühl, dass viele dieser Probleme darauf zurückzuführen sind, dass die Leute nicht vollständig verstehen, was mit ihrem Bundler passiert (was verständlich ist), aber diese Probleme sind nicht nur auf drei beschränkt. Es ist jedoch möglich, dass das versehentliche Doppelimportieren von drei Kernen nur auffälliger ist als bei anderen Bibliotheken. Das Bündeln einer Abhängigkeit, die extern sein soll, wie Lodash, eine Reaktionskomponente oder OrbitControls, kann leichter übersehen werden.

Dieses Verhalten in Bezug auf Abhängigkeit von einem externen Paket dokumentiert Rollup und bietet eine Option , hier und Webpack hat eine ähnliche Option hier . Wenn sich die Beispieldateien in diesem Fall stattdessen auf "drei" beziehen, erhalten Sie, obwohl die Kernbibliothek nicht gebündelt wäre, immer noch doppelte Bündel mit Beispielcode, was ein eigenes Problem darstellt. Und ich glaube nicht, dass dieses Projekt irgendetwas tun kann, um einem Bundler bei der Interpretation der Fallstricke von npm-Links zu helfen. Ich denke, der einzige problematische Fall, den ich gesehen habe und der meiner Meinung nach nicht das Ergebnis eines falsch konfigurierten Bundlers ist, ist der Codesandbox-Fall.

Für Bundler-Fälle besteht die Antwort möglicherweise darin, zu dokumentieren, eine Anleitung zur Fehlerbehebung hinzuzufügen oder einen Link zur Konfiguration der allgemeinen Bundler auf der Seite Importieren über Module hinzuzufügen.

Ich habe eine Ahnung, dass, wenn examples/jsm Pakete dieses Muster ändern könnten...

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

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

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

... diese Probleme wären viel einfacher zu lösen. Leider weiß ich nicht, wie wir die HTML-Beispiele innerhalb der Threejs-Website ohne ein komplexes Build-Setup verwalten würden. Ein Import-Map-Polyfill auf der Threejs-Website könnte das Problem lösen, aber ich bin mir nicht sicher. :/

Wenn sich die Beispieldateien stattdessen auf "drei" beziehen, erhalten Sie, obwohl die Kernbibliothek nicht gebündelt wäre, immer noch doppelte Bündel mit Beispielcode ...

Ich kann dem nicht ganz folgen. Weil es sich um relative Pfadimporte handelt? Wir könnten sie paketbezogen machen.

@donmccurdy

Ich habe eine Ahnung, dass, wenn Beispiele/jsm-Pakete dieses Muster ändern könnten, diese Probleme viel einfacher zu lösen wären.

Ich denke, dies würde es aussehen lassen, als ob es gelöst wäre, aber die Leute hätten immer noch doppelten Code, der nur schwerer zu bemerken ist, weil er nicht dazu führt, dass die Anwendung kaputt geht.

Ich kann dem nicht ganz folgen. Weil es sich um relative Pfadimporte handelt? Wir könnten sie paketbezogen machen.

Tut mir leid, wenn ich mir nicht klar bin, ich denke, das ist etwas schwer zu erklären - hoffentlich ist das etwas klarer. Ich verwende den Rollup-Fall:

In den obigen Fällen, in denen Leute ein Paket mit three möchten, das als extern markiert ist, gehe ich davon aus, dass sie eine Bibliothek erstellen, in der Three.js eine Peer-Abhängigkeit wäre, auf die sich eine andere Anwendung verlassen könnte:

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

Hier wäre das Ziel, dass die oben genannten Three.js-Importe in der Bibliothek verbleiben und das Bundle drei und OrbitControls als Peer-Abhängigkeiten lädt. Wenn die Anwendung also auch drei.js und OrbitControls verwendet, importieren Sie beide nicht zweimal.

Die Leute erwarten, dass die Option external: [ 'three' ] dieses Verhalten für sie erreicht (ich habe es sicherlich getan), aber das ist nicht der Fall, weil die Zeichenfolge nicht mit dem OrbitControls-Importpfad übereinstimmt. Dies führt dazu, dass OrbitControls unbeabsichtigt gebündelt wird und daher auch ../../../build/three.module.js gebündelt wird (weil es auch nicht mit dem String übereinstimmt). Ich denke, die Leute weisen darauf hin, dass die Three.js-Kerndatei gebündelt wird, weil sie viel auffälliger ist – die Anwendungen gehen kaputt, das Bibliotheksbündel ist viel größer usw. – wo die Realität ist, dass _die OrbitControls-Datei nicht in der an erster Stelle._ Der richtige Weg, Rollup hier zu konfigurieren, besteht darin, die Option auf external: path => /^three/.test( path ) .

Dies ist nicht nur bei dreien der Fall. Rollup verwendet Lodash als Beispiel in seinen Dokumenten, aber es wird schwer / unmöglich zu bemerken sein, wenn 'lodash/merge' in Ihrem Bibliothekscode gebündelt wird, weil es so klein ist und keine doppelten Importfehler verursacht. Die Material-Benutzeroberfläche fördert verschachtelte Dateireferenzen in Importen und ebenso würde die Einstellung external: ['@material-ui/core'] '@material-ui/core/Button' aus dem Bundle ausschließen.

Ich denke nicht, dass es sich lohnt, den Beispielcode für diese Anwendungsfälle zu ändern, da dies immer noch zu doppeltem Code führt, der bei richtiger Konfiguration des Bundles nicht vorhanden wäre.

Zwei Fälle hier:

(1) Benutzer möchte einmal dreijs und Beispiele enthalten, bekommt etwas zweimal

ZB beim Erstellen einer Anwendung.

(2) Benutzer möchte Threejs und Beispiele null Mal enthalten, bekommt etwas mehr als 1 Mal

ZB beim Aufbau einer Bibliothek mit drei als externe oder Peer-Abhängigkeit.


Soweit ich weiß, sind sowohl (1) als auch (2) immer noch leichte Probleme, in die man stolpern kann? Wenn der obige Ansatz (1) löst, ist das allein hilfreich. Bei (2) bin ich mir nicht sicher. Vielleicht sollte der /^three/.test( path ) Trick beim Import über Module erwähnt werden ?

@gkjohnson Danke für diese Erklärung, sie hat mir wirklich geholfen, meine Gedanken zu klären

In meiner Rollup-Konfiguration habe ich external diese Weise definiert

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

Ich dachte, es würde funktionieren, da drei als externe Abhängigkeiten behandelt würden; aber wie Sie bereits erwähnt haben, müssen Sie eine Regex verwenden (soweit ich das verstanden habe, liegt es wohl daran, dass die Beispiele funktionieren
import from "../../../build/three.module.js"; ). Also habe ich es geschafft

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

Es ist eine etwas unzusammenhängende Frage, aber ich würde erwarten, dass alle Abhängigkeiten, die ich in package.json deklariert habe, nicht Teil des Pakets sind. Ist das eine richtige Annahme?

@donmccurdy

Soweit ich weiß, sind sowohl (1) als auch (2) immer noch leichte Probleme, in die man stolpern kann?

Meiner Meinung nach ist (2) das Ergebnis einer falschen Konfiguration des Bundlers und vielleicht können wir das beheben, indem wir die Dokumentation mit einigen Vorschlägen für Bundler aktualisieren. (1) kann als Folge der Verwendung eines Pakets auftreten, das unter einem Problem (2) leidet, aber ansonsten bin ich nicht überzeugt, dass (1) leicht zu stolpern ist. Ich würde gerne einen realen Anwendungsfall sehen, der das Problem demonstriert, um zu sehen, wie jemand seinen Bundler konfiguriert hat, aber hier ist eine Liste der Möglichkeiten, wie ich weiß, dass Sie dies (bisher) erreichen können:

  1. Explizit von 'three/src/Three.js' oder 'three/build/three.min.js' importieren (was in den Dokumenten nicht empfohlen wird).
  2. Konfigurieren Sie Ihren Bundler so, dass beim Auflösen das Feld package.main anstelle des Felds package.module wird. Die drei großen Bundler Rollup , Webpack und Parcel bevorzugen jedoch standardmäßig module gegenüber main . Dieser Anwendungsfall scheint ungewöhnlich zu sein, aber das ist nur eine Annahme.
  3. Verwenden Sie npm link , um ein symbolverknüpftes Paket einzuschließen, das von drei abhängt (dies wird mit der Option preserveSymlinks von Rollup behoben).
  4. Verwenden Sie drei Beispiele und Beispiele in Codesandbox.io, da die Plattform das Hauptfeld gegenüber dem Modul priorisiert.

Nummer 4 scheint die einzige zu sein, über die man leicht stolpern könnte, obwohl ich weiß, dass die Leute 1 für Baumschütteln tun. Die anderen haben das Gefühl, dass sie außerhalb unserer Kontrolle sind oder sehr selten sind.

@chabb

Soweit ich das verstanden habe, liegt es wohl daran, dass die Beispiele import from "../../../build/three.module.js"; tun ...

Dies ist nicht der Fall, bitte lesen Sie, was ich hier erklärt habe: https://github.com/mrdoob/three.js/issues/17482#issuecomment -583694493. /^three funktioniert, weil es mit der Zeichenfolge 'three/examples/jsm/controls/OrbitControls.js' übereinstimmt, die auch extern sein sollte, da sie Teil der Three.js-Bibliothek ist, während die Zeichenfolge 'three' dies nicht tut. Das gleiche kann auch mit anderen Abhängigkeiten passieren. Ich würde empfehlen, Regex für alle Abhängigkeiten zu verwenden, um andere unbekannte Fallstricke zu vermeiden oder mit einem Paket mit einem bloßen Modulbezeichner abzugleichen.

@gkjohnson Danke für die ausführliche Erklärung, das macht für mich Sinn.

Es hört sich so an, als würde dies das Problem in diesem Thread nicht lösen, aber da ich es bereits ein paar Mal im Thread erwähnt habe, habe ich endlich ein Import-Map-Polyfill getestet: https://github.com/KhronosGroup/ KTX-Software/pull/172/files. Mit diesem Polyfill funktioniert import * as THREE from 'three'; im Webbrowser.

Wenn nur der Browser etwas Vertrauen zeigen würde...
https://github.com/WICG/import-maps/issues/212#issuecomment -663564421

Ich bin auf das gleiche Problem gestoßen, als ich einem meiner Projekte eine Pass-Unterklasse hinzugefügt habe

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

Und da ich es vorzog, den Pass-Code in mein Modul zu kopieren, um ihn später nicht aus Three.js im Browser importieren zu müssen, habe ich einen Workaround gefunden:

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

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

Auf diese Weise funktioniert es mit Browsern und Modulimporte sollten ebenfalls funktionieren.

Bearbeiten :

Das Laden von einem lokalen drei Projekt (siehe Beispiel unten) wird diesen Ansatz unterbrechen und einige zusätzliche Problemumgehung erfordern.

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

Nun, ich habe eine neue Version erstellt, die den lokalen Link unterstützt:

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 Dies wurde oben in https://github.com/mrdoob/three.js/issues/17482#issuecomment -530957570 behandelt. Wenn Sie Rollup verwenden und bei Verwendung von Beispielmodulen three.js als extern markieren möchten, müssen Sie wie vorgeschlagen Folgendes tun:

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

Es gibt keinen Grund, die Konfiguration so kompliziert zu machen. Dadurch wird sichergestellt, dass sowohl die Datei Pass.js als auch das Modul Three.js als extern gekennzeichnet sind.

@gkjohnson Mein Anwendungsfall ist nicht genau derselbe, da ich nur möchte, dass die three Bibliothek als extern markiert wird, nicht das Beispiel (ich möchte, dass das Beispiel mit meinem Build gebündelt wird).

Ich baue eine Bibliothek mit drei als externe, ich möchte, dass das Beispiel in der Breite des Builds gebündelt wird, aber ohne drei, und wie oben beschrieben, enthält die Ausgabe beim Importieren eines Moduls aus Beispielen den Code von drei. Ist das mit Webpack möglich?

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

@Mcgode @recardinal Ich glaube nicht, dass es möglich ist. Ich wollte dasselbe tun, also habe ich einfach den Code aus den Beispielen kopiert / eingefügt; In meinem Fall musste ich die Importe und Exporte 'anpassen' und das wars. Natürlich ist dies nicht ideal, aber für meinen Anwendungsfall war es gut genug.

Ich habe hier einen ähnlichen Anwendungsfall mit Webpack und THREE als externem. Die folgenden Importe bewirken, dass drei.module.js in die gebündelte Ausgabe eingeschlossen werden.

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

Ich habe irgendwo gelesen, dass Beispiele/js/* irgendwann entfernt werden. Es wäre schön, wenn die jsm-Beispiele vorher "einfach funktionieren".

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

jonobr1 picture jonobr1  ·  95Kommentare

lmcd picture lmcd  ·  74Kommentare

sunag picture sunag  ·  161Kommentare

fernandojsg picture fernandojsg  ·  85Kommentare

qornflex picture qornflex  ·  113Kommentare