Three.js: Mengimpor contoh modul jsm menyebabkan bundler membundel kode sumber three.js dua kali

Dibuat pada 12 Sep 2019  ·  43Komentar  ·  Sumber: mrdoob/three.js

Mengimpor dari three/examples/jsm/.../<module> menyebabkan bundler (diuji dengan rollup) menyertakan pustaka dua kali (atau beberapa kali).

Misalnya, saat melakukan import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' , bundler akan mengikuti impor dan di OrbitControls.js impor berasal dari ../../../build/three.module.js . Namun, tidak ada cara bagi bundler (eksternal) untuk mengetahui bahwa ../../../build/three.module.js adalah modul yang sama dengan three .

Solusi untuk ini adalah memperlakukan modul contoh sebagai paket eksternal dan mengimpor dari three alih-alih ../../../build/three.module.js . Ini mungkin merusak konfigurasi rollup three.js, tetapi seharusnya memungkinkan untuk memberi tahu rollup bahwa three adalah alias untuk titik masuk utama tiga ( src/Three.js ).

Komentar yang paling membantu

Saya pikir itu hanya sesuatu untuk membiasakan diri. Sekarang saya pikir saya mengerti, saya baik-baik saja dengan apa adanya.

BTW saya memperbarui threejsfundamentals menjadi semua berbasis esm jadi

Semua 43 komentar

(diuji dengan rollup)

Saya tidak dapat mengkonfirmasi ini dengan rollup. Jika Anda melakukannya seperti dalam pengaturan proyek berikut, semuanya berfungsi seperti yang diharapkan.

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

Jika Anda memperlakukan three sebagai ketergantungan eksternal:

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

maka output tidak boleh berisi kode sumber three.js, namun mencakup semuanya.

Namun, jika Anda tidak mengimpor OrbitControls, maka output hanya akan menyertakan kode sumber dari file main.js .

anda dapat mencobanya dengan mengomentari impor OrbitControls , dan kemudian membangun lagi (tetapi dengan 'three' sebagai ketergantungan eksternal).

Ini terkait dengan #17220 -- salah satu solusi yang diusulkan adalah mengganti bidang main di package.json dengan jalur pembuatan modul tetapi itu tidak akan memperbaiki kasus penggunaan ini.

Untuk memperjelas masalahnya di sini adalah bahwa sementara three ditandai sebagai eksternal untuk membangun paket terpisah yang bergantung pada tiga dalam konfigurasi rollup yang tidak menangkap referensi keras ke ../../../build/three.module.js dan memasukkannya ke dalam build. Misalnya membangun file berikut secara tidak sengaja akan menyertakan kode OrbitControls _dan_ kode threejs dalam bundel, serta mengimpor salinan tiga lainnya ketika dibangun dengan konfigurasi yang diposting @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 mungkin perlu dicatat bahwa meskipun jalur di OrbitControls.js diubah menjadi three OrbitControls akan tetap disertakan dalam bundel Anda yang mungkin diinginkan atau tidak dan dapat menghasilkan setidaknya kode OrbitControls dimasukkan dua kali dalam aplikasi dependen.

Saya tidak bermaksud mengusulkan ini sebagai solusi jangka panjang atau terbaik tetapi mengubah konfigurasi untuk menandai OrbitControls (dan semua file dalam tiga folder) sebagai eksternal akan menyelesaikan ini dalam kedua kasus:

export default {
    // ...

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

    // ...
};

Saya tidak bermaksud mengusulkan ini sebagai solusi jangka panjang atau terbaik tetapi mengubah konfigurasi untuk menandai OrbitControls (dan semua file dalam tiga folder) sebagai eksternal akan menyelesaikan ini dalam kedua kasus:

Untuk beberapa alasan saya mengharapkan rollup untuk memperlakukan 'three/examples/jsm/controls/OrbitControls.js' sebagai eksternal juga secara default. Jadi solusi yang Anda usulkan bagus untuk kasus penggunaan saya.

#17220 terkait sangat relevan. Percakapan mungkin harus berlanjut di sana.

Jadi apa yang terjadi jika Anda melakukan ini?

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

Itu akan berhasil, tetapi itu tidak layak, karena lib atau bagian kode lain yang bergantung pada tiga akan diimpor dari "tiga" dan kemudian rusak lagi. Package.json biasanya memberi tahu lingkungan cara mengatasinya, "build/three.module" adalah detail distribusi yang tidak boleh bocor. Ketika resolusi dilewati itu hanya mengundang masalah namespace.

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

@gkjohnson Bagaimana jika pengguna ingin memasukkan instance "tiga" dan OrbitControls dalam bundel?

Tidak yakin ini terkait hal serupa terjadi jika Anda mencoba menggunakan modul langsung seperti ini

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

memuat three.js dua kali, sekali dari CDN dan sekali lagi dari threejs.org

Mungkin bukan itu cara modul seharusnya digunakan dengan tiga tetapi hanya dari pra 106 ada 1000-an situs dan contoh yang melakukannya

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

Semua contoh menunjukkan menggunakan modul langsung alih-alih membangun (bundling) sehingga dalam arti mereka tidak menunjukkan cara sebenarnya untuk menggunakan three.js seperti dulu. Dengan kata lain, contoh-contoh lama bekerja di luar kotak. Contoh baru tidak AFAIK. Agar contoh berfungsi, Anda perlu mengekstrak JavaScript dari contoh dan memasukkan file .js terpisah, lalu meletakkan three.js secara lokal (mungkin melalui npm). Perbaiki semua jalur dalam contoh sehingga mereka adalah jalur berbasis paket (tidak ada ../.././build), dan akhirnya gunakan rollup

Itu perubahan yang cukup besar dari versi non modul yang hanya mengubah jalurnya saja

@mrdoob

Dengan konfigurasi asli @adrian-delgado, three.js akan disertakan sekali dan kontrol orbit akan disertakan sekali dan tidak ada paket yang akan ditandai sebagai eksternal. Dengan konfigurasi yang saya usulkan akan ada ketergantungan eksternal pada three/build/three.module.js dan three/examples/jsm/controls/OrbitControls.js dalam bundel yang dihasilkan.

@EliasHasle

Bagaimana jika pengguna ingin memasukkan instance "tiga" dan OrbitControls dalam bundel?

Kemudian bidang external harus dikecualikan dalam hal ini satu salinan dari tiga dan kontrol orbit akan disertakan dalam bundel. rollup-plugin-node-resolve (yang diperlukan untuk rollup untuk mendukung resolusi modul dan sedang digunakan dalam konfigurasi di atas) default untuk menggunakan bidang modul package.json (lihat opsi mainFields ) sehingga orbit mengontrol tiga referensi dan "tiga" akan menyelesaikan skrip yang sama. _Jika mainFields diubah menjadi ["main", "module"] jadi "main" digunakan sebagai ganti "modul" di package.json_ maka dua salinan dari tiga akan disertakan di sini dan semuanya akan rusak dengan cara yang telah disebutkan sebelumnya. Namun itu memang membutuhkan mengubah bidang itu. Namun, jika "main" digunakan, maka rollup-plugin-commonjs kemungkinan juga akan diperlukan, karena rollup tidak mengetahui cara memproses file commonjs yang menggunakan require secara default.

@greggman

Sayangnya saya tidak berpikir penggantian modul yang naif akan bekerja dengan mudah dalam kasus ini. Tak satu pun dari solusi yang diusulkan akan menangani kasus ini dan saya tidak berpikir ada sesuatu yang resmi saat ini yang dapat digunakan untuk membantu kasus mengimpor skrip inti dan contoh dari host yang terpisah. Peta impor adalah satu-satunya hal yang sedang dikerjakan untuk membantu ini sejauh yang saya tahu. Jika contoh dan tiga diimpor dari host yang sama maka hanya satu salinan dari tiga yang akan dimuat:

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

Bergantung pada kasus penggunaan, mungkin lebih baik untuk terus menggunakan tag skrip klasik?

@greggman

Tidak yakin ini terkait hal serupa terjadi jika Anda mencoba menggunakan modul langsung seperti ini

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

Iya... Jangan pake modul gitu 😁

Iya... Jangan pake modul gitu 😁

Sepakat. Bisa dibilang dokumen dan contoh menargetkan sebagian besar pengembang yang tidak berpengalaman dan fakta bahwa contoh jsm adalah default dan tidak ada dari mereka yang akan berfungsi tanpa pembangun atau mereka tidak akan bekerja melalui CDN apa pun adalah semacam perubahan besar.

Dulu Anda pada dasarnya dapat melihat sumber pada contoh, menyalin dan menempel ke jsfiddle/codepen dll, memperbaiki jalur di tag skrip dan itu akan berjalan. Sekarang meskipun semua contoh tidak akan berjalan kecuali Anda menautkan langsung ke situs three.js dan melihatnya rusak setiap kali versinya terbentur. (ya saya tahu contoh non modul ada tetapi itu bukan yang ditautkan dari 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';

Tidak berfungsi, OrbitControls tidak ada di CDN dan jalur di dalam OrbitContrls ../../../build/three.js bukan jalur yang benar untuk membuatnya berfungsi

// atau

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

Juga tidak berfungsi karena akan rusak setiap kali three.js mendorong versi baru

Mungkin Dorong folder contoh/js ke CDN dan tiga sehingga hanya memperbaiki url dalam kode contoh masih akan berfungsi? Itu berarti three.module.js harus berada di

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

build ditambahkan ke jalur

Dulu Anda pada dasarnya dapat melihat sumber pada contoh, menyalin dan menempel ke jsfiddle/codepen dll, memperbaiki jalur di tag skrip dan itu akan berjalan ...

Saya pikir kita perlu mengimpor peta untuk melakukan sesuatu yang berguna tentang itu, baik atau buruk.

Sekarang meskipun semua contoh tidak akan berjalan kecuali Anda menautkan langsung ke situs three.js

Saya benar-benar tidak akan mendorong siapa pun untuk menautkan langsung ke skrip langsung di situs threejs ... itu tidak akan pernah menjadi ide yang baik. Ada alternatif berversi, per komentar di atas.

Dokumentasi yang idealnya akan menjawab pertanyaan-pertanyaan ini adalah halaman Impor melalui modul . Apakah ada kasus yang harus kita bahas di sana? Saya kira menyebutkan CDN akan menjadi ide yang bagus.

Menyebutkan CDN adalah ide yang bagus. Juga menyebutkan bahwa CDN cloudflare, hit pertama, di Google tidak bagus untuk modul (kecuali itu berubah)

@greggman

Dulu Anda pada dasarnya dapat melihat sumber pada contoh, menyalin dan menempel ke jsfiddle/codepen dll, memperbaiki jalur di tag skrip dan itu akan berjalan.

Aku di pihakmu. Bagian terburuk dari modul adalah Anda tidak dapat mengakses camera atau renderer dari konsol dalam contoh lagi

Bagaimana kalau kita mulai menggunakan unpkg?

Maksud Anda mulai menggunakannya dalam dokumentasi seperti halaman Impor melalui modul , atau menggunakannya dalam proyek entah bagaimana?

Bagian terburuk dari modul adalah Anda tidak dapat mengakses kamera atau perender dari konsol dalam contoh lagi

Ya, itu membuat frustrasi. Saya telah melemparkan ini (atau serupa) ke dalam contoh saat mengembangkan secara lokal:

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

Saya berasumsi itu adalah sesuatu yang kami harap dapat diselesaikan dengan ekstensi alat dev?

Satu ide yang membutuhkan penyelidikan, tetapi bisa menarik... jika kita bersedia menambahkan polyfill peta impor ke semua contoh, saya pikir kita bisa membuat impor yang digunakan di sana 100% kompatibel dengan npm- dan alur kerja berbasis bundler. Sebagai contoh:

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

Bagaimana kalau kita mulai menggunakan unpkg?

Maksud Anda mulai menggunakannya dalam dokumentasi seperti halaman Impor melalui modul, atau menggunakannya dalam proyek entah bagaimana?

Alih-alih menunjuk ke https://threejs.org/build/. Saat ini kami menggunakan tautan itu di ISSUE_TEMPLATE .

Dan @greggman mungkin bisa beralih dari https://cdnjs.cloudflare.com/ajax/libs/three.js/108/ ke https://unpkg.com/[email protected]/ ?

Sepertinya unpkg memecahkan masalah yang sedang kita diskusikan di sini.

Ya, itu membuat frustrasi. Saya telah melemparkan ini (atau serupa) ke dalam contoh saat mengembangkan secara lokal:

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

Ugh! Ha ha

Saya berasumsi itu adalah sesuatu yang kami harap dapat diselesaikan dengan ekstensi alat dev?

Ya! 🤞

@greggman

Tidak yakin ini terkait hal serupa terjadi jika Anda mencoba menggunakan modul langsung seperti ini

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

Iya... Jangan pake modul gitu 😁

Jadi hari ini saya mendapati diri saya melakukan hal itu... Itu memang kebiasaan buruk, tetapi masalahnya adalah sebagian besar hal berhasil tetapi jika ada yang rusak cukup sulit untuk diatasi.

Dalam kasus saya, saya mengimpor three.module.js dari dev dan OBJLoader dari master . OBJLoader mengimpor three.module.js dari master sehingga BufferGeometry tidak memiliki properti usage , dan WebGLRenderer melakukannya tidak merender mesh karena tidak menemukan usage , yang lainnya berfungsi

Ini cukup berbulu...

Saya pikir itu hanya sesuatu untuk membiasakan diri. Sekarang saya pikir saya mengerti, saya baik-baik saja dengan apa adanya.

BTW saya memperbarui threejsfundamentals menjadi semua berbasis esm jadi

Sepertinya bagus untuk memiliki three.module.min.js meskipun (atau itu three.min.module.js )

+1

Saya baru saja mengimpor tiga & kontrol orbit sebagai modul ES6 & karena (tampaknya) kontrol orbit mengacu pada tiga di dalam folder build, saya perlu beberapa saat untuk mengetahui jalur saya

Super fan kita dapat menggunakan tiga sebagai modul, tetapi akan menyenangkan untuk memiliki lebih banyak fleksibilitas di sekitar ini, saya tidak akan masuk ke file kontrol orbit dan mulai mengotak-atik, dengan asumsi ini adalah kasus dengan modul lain juga.

Juga +1 untuk three.min.module.js

pindah dari #18239, saya terjebak di dalamnya masalah yang sama dengan melakukan npm link pada paket lain yang menggunakan three.js.

Saya telah mengembangkan plugin tiga-minifier yang dapat membantu memecahkan masalah ini.

Saya menghadapi masalah yang sama. Saya sedang menulis komponen React menggunakan three.js, dan saya mengimpor beberapa modul dari contoh. Setelah dibundel dengan rollup, jika saya melihat bundel, saya dapat melihat bahwa ada satu pernyataan impor untuk tiga, dan kemudian kode Three.js.

Jika saya menggunakan pernyataan impor ini di komponen saya: import * as THREE from "three/build/three.module"
semuanya berfungsi dengan benar tetapi Tiga kemudian disematkan dalam bundel, yang merupakan sesuatu yang tidak saya inginkan.
Saya ingin memiliki pernyataan impor untuk tiga. Jika saya menggunakan import * as THREE from "three , bundel akan memiliki tiga yang diimpor sebagai modul, tetapi segera setelah saya menggunakan salah satu contoh, maka three.js ditambahkan dalam bundel ( = saya memiliki satu pernyataan impor untuk tiga, dan kemudian kode tiga ), yang pada akhirnya menyebabkan kode saya rusak

@chabb

Saya sedang menulis komponen React menggunakan three.js, dan saya mengimpor beberapa modul dari contoh. Setelah dibundel dengan rollup, jika saya melihat bundel, saya dapat melihat bahwa ada satu pernyataan impor untuk tiga, dan kemudian kode Three.js.

Solusi yang diposting di sini harus menyelesaikan masalah Anda: https://github.com/mrdoob/three.js/issues/17482#issuecomment -530957570.

Saya merasa banyak masalah ini berasal dari orang yang tidak sepenuhnya memahami apa yang terjadi dengan bundler mereka (yang dapat dimengerti) tetapi masalah ini tidak unik untuk tiga. Namun, mungkin saja, pengimporan ganda tiga inti secara tidak sengaja hanya lebih terlihat daripada dengan perpustakaan lain. Menggabungkan dependensi yang dimaksudkan untuk menjadi eksternal seperti lodash, komponen reaksi, atau OrbitControls dapat lebih mudah dilewatkan.

Mengenai bergantung pada paket eksternal Rollup mendokumentasikan perilaku ini dan menyediakan opsi di sini dan Webpack memiliki opsi serupa di sini . Dalam hal ini jika file contoh alih-alih merujuk ke "tiga" maka sementara perpustakaan inti tidak akan dibundel, Anda masih akan mendapatkan kumpulan duplikat kode contoh yang merupakan masalahnya sendiri. Dan saya rasa tidak ada yang bisa dilakukan proyek ini untuk membantu bundler menafsirkan jebakan tautan npm. Saya pikir satu-satunya kasus bermasalah yang pernah saya lihat yang saya rasa bukan hasil dari bundler yang salah konfigurasi adalah kasus kode dan kotak.

Untuk kasus bundler mungkin jawabannya adalah mendokumentasikan, menambahkan panduan pemecahan masalah, atau tautan ke cara mengonfigurasi bundler umum pada halaman pengimporan melalui modul .

Saya punya firasat bahwa jika paket examples/jsm dapat mengubah pola ini...

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

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

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

... masalah ini akan jauh lebih mudah untuk diselesaikan. Sayangnya, saya tidak tahu bagaimana kami akan mengelola contoh HTML dalam situs web threejs tanpa pengaturan build yang rumit. Polyfill peta impor di situs web threejs mungkin menyelesaikannya, tetapi saya tidak yakin. :/

jika file contoh malah merujuk ke "tiga" maka sementara perpustakaan inti tidak akan dibundel, Anda masih akan mendapatkan kumpulan duplikat kode contoh ...

Saya tidak begitu mengikuti ini. Karena mereka adalah jalur impor relatif? Kita bisa membuatnya relatif paket.

@donmccurdy

Saya punya firasat bahwa jika paket contoh/jsm dapat mengubah pola ini... masalah ini akan lebih mudah diselesaikan.

Saya pikir ini akan membuatnya terlihat terselesaikan tetapi orang-orang masih memiliki kode duplikat yang lebih sulit untuk diperhatikan karena tidak menyebabkan aplikasi rusak.

Saya tidak begitu mengikuti ini. Karena mereka adalah jalur impor relatif? Kita bisa membuatnya relatif paket.

Maaf jika saya tidak jelas Saya pikir ini agak sulit untuk dijelaskan -- semoga ini sedikit lebih jelas. Saya akan menggunakan kasus Rollup:

Dalam kasus di atas di mana orang ingin menggulung paket dengan three ditandai sebagai eksternal, saya berasumsi mereka sedang membangun perpustakaan di mana three.js akan menjadi ketergantungan rekan yang dapat diandalkan oleh aplikasi lain:

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

Di sini tujuannya adalah agar impor three.js di atas tetap berada di perpustakaan dan bundel memuat tiga dan OrbitControls sebagai dependensi rekan jadi jika aplikasi juga menggunakan three.js dan OrbitControls Anda tidak mengimpor keduanya dua kali.

Orang mengharapkan opsi external: [ 'three' ] untuk mencapai perilaku ini untuk mereka (saya tentu saja melakukannya) tetapi tidak karena string tidak cocok dengan jalur impor OrbitControls. Ini menghasilkan OrbitControls secara tidak sengaja dibundel dan oleh karena itu ../../../build/three.module.js juga dibundel (karena itu juga tidak cocok dengan string). Saya pikir orang-orang menunjuk ke file inti three.js yang dibundel karena itu jauh lebih terlihat -- aplikasi rusak, bundel perpustakaan jauh lebih besar, dll -- di mana kenyataannya adalah file _OrbitControls seharusnya tidak dibundel dalam tempat pertama._ Cara yang benar untuk mengkonfigurasi Rollup di sini adalah dengan mengatur opsi ke external: path => /^three/.test( path ) .

Ini tidak unik untuk tiga. Rollup menggunakan lodash sebagai contoh dalam 'lodash/merge' dibundel dalam kode perpustakaan Anda karena sangat kecil dan tidak akan menyebabkan bug impor duplikat. Material UI mendorong referensi file bersarang dalam impor dan juga pengaturan external: ['@material-ui/core'] akan gagal mengecualikan '@material-ui/core/Button' dari bundel.

Saya pikir tidak ada gunanya mengubah kode contoh untuk kasus penggunaan ini karena masih akan menghasilkan kode duplikat yang tidak akan ada jika bundler dikonfigurasi dengan benar.

Dua kasus di sini:

(1) pengguna ingin threejs dan contoh disertakan sekali, mendapat sesuatu dua kali

Misalnya saat membangun aplikasi.

(2) pengguna menginginkan tiga dan contoh termasuk nol kali, mendapatkan sesuatu 1+ kali

Misalnya saat membangun perpustakaan dengan tiga sebagai ketergantungan eksternal atau rekan.


Sejauh yang saya tahu baik (1) dan (2) masih masalah mudah tersandung? Jika pendekatan di atas menyelesaikan (1), itu saja sudah membantu. Saya tidak yakin tentang (2). Mungkin trik /^three/.test( path ) harus disebutkan pada import via modules ?

@gkjohnson Terima kasih atas penjelasan ini, itu sangat membantu saya memperjelas pikiran saya

Dalam konfigurasi rollup saya, saya mendefinisikan external dengan cara ini

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

Saya pikir itu akan berhasil, karena tiga akan diperlakukan sebagai dependensi eksternal; tetapi seperti yang Anda sebutkan, Anda harus menggunakan regex (sejauh yang saya mengerti, saya kira itu karena contohnya sedang dilakukan
import from "../../../build/three.module.js"; ). Jadi saya akhirnya melakukan

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

Ini pertanyaan yang agak tidak terkait, tetapi saya berharap bahwa semua dependensi yang saya nyatakan di package.json bukan bagian dari bundel? Apakah itu asumsi yang benar?

@donmccurdy

Sejauh yang saya tahu baik (1) dan (2) masih masalah mudah tersandung?

Menurut pendapat saya (2) adalah hasil dari konfigurasi bundler yang salah dan mungkin kami dapat mengatasinya dengan memperbarui dokumen dengan beberapa saran untuk bundler. (1) dapat terjadi akibat penggunaan paket yang bermasalah (2) tetapi selain itu saya tidak yakin (1) mudah tersandung. Saya ingin melihat kasus penggunaan dunia nyata yang menunjukkan masalah untuk melihat bagaimana seseorang mengonfigurasi bundler mereka, tetapi inilah daftar cara yang saya tahu Anda dapat mencapai ini (sejauh ini):

  1. Impor secara eksplisit dari 'three/src/Three.js' , atau 'three/build/three.min.js' (yang tidak disarankan dalam dokumen).
  2. Konfigurasi ulang bundler Anda untuk menggunakan bidang package.main daripada bidang package.module saat menyelesaikan. Tiga bundler besar Rollup , Webpack , dan Parcel semuanya lebih suka module daripada main secara default. Kasus penggunaan ini terasa tidak biasa tetapi itu hanya asumsi.
  3. Gunakan npm link untuk menyertakan paket symlink yang bergantung pada tiga (ini diperbaiki dengan menggunakan opsi preserveSymlinks rollup)
  4. Gunakan tiga dan contoh di codesandbox.io karena platform memprioritaskan bidang utama daripada modul .

Nomor 4 sepertinya satu-satunya yang bisa ditemukan dengan mudah, meskipun saya tahu orang melakukan 1 untuk menggoyang pohon. Yang lain merasa seperti mereka berada di luar kendali kami atau akan sangat tidak biasa.

@chabb

sejauh yang saya mengerti, saya kira itu karena contohnya melakukan import from "../../../build/three.module.js"; ...

Ini bukan masalahnya, silakan baca apa yang saya jelaskan di sini: https://github.com/mrdoob/three.js/issues/17482#issuecomment -583694493. /^three berfungsi karena cocok dengan string 'three/examples/jsm/controls/OrbitControls.js' yang juga harus eksternal karena merupakan bagian dari perpustakaan three.js sedangkan string 'three' tidak. Hal yang sama dapat terjadi dengan dependensi lain juga. Saya akan merekomendasikan menggunakan regex untuk semua dependensi untuk menghindari jebakan lain yang tidak diketahui atau mencocokkan dengan paket apa pun dengan penentu modul kosong.

@gkjohnson Terima kasih atas penjelasan rincinya, itu masuk akal bagi saya.

Sepertinya ini tidak menyelesaikan masalah di utas ini, tetapi karena saya telah menyebutkannya beberapa kali di utas, saya akhirnya menguji polyfill peta impor: https://github.com/KhronosGroup/ KTX-Software/pull/172/file. Dengan polyfill itu, import * as THREE from 'three'; bekerja di browser web.

Andai saja browser menunjukkan kepercayaan diri...
https://github.com/WICG/import-maps/issues/212#issuecomment -663564421

Saya mengalami masalah yang sama saat menambahkan subkelas pass ke salah satu proyek saya

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

Dan karena saya lebih suka menyalin kode Pass di modul saya, agar tidak perlu mengimpornya nanti dari three.js di browser, saya terus mencari solusi:

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

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

Dengan cara ini, ini berfungsi dengan browser, dan impor modul juga akan berfungsi.

Sunting :

Memuat dari tiga proyek lokal (lihat contoh di bawah) akan merusak pendekatan ini dan memerlukan beberapa solusi tambahan.

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

Yah, saya melanjutkan dan membuat versi baru yang mendukung tautan lokal:

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 Ini telah dibahas di atas di https://github.com/mrdoob/three.js/issues/17482#issuecomment -530957570. Jika Anda menggunakan Rollup dan ingin menandai three.js sebagai eksternal saat menggunakan modul contoh, Anda harus melakukan hal berikut seperti yang disarankan:

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

Tidak ada alasan untuk membuat konfigurasi begitu rumit. Ini akan memastikan bahwa file Pass.js dan modul three.js ditandai sebagai eksternal.

@gkjohnson Kasus penggunaan saya tidak persis sama, karena saya hanya ingin lib three ditandai sebagai eksternal, bukan contoh (saya ingin contoh dibundel dengan build saya).

Saya sedang membangun perpustakaan dengan tiga sebagai eksternal, saya ingin contoh dibundel dengan lebar build tetapi tanpa tiga, dan seperti yang dibahas di atas, ketika mengimpor modul dari contoh, output akan berisi kode tiga. Apakah mungkin untuk mencapai dengan webpack?

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

@Mcgode @recardinal Saya rasa itu tidak mungkin. Saya ingin melakukan hal yang sama jadi saya hanya menyalin/menempelkan kode dari contoh; dalam kasus saya, saya harus 'menyesuaikan' impor dan ekspor dan hanya itu. Jelas ini tidak ideal tetapi cukup baik untuk kasus penggunaan saya.

Saya memiliki kasus penggunaan serupa di sini dengan Webpack dan THREE sebagai eksternal. Impor berikut menyebabkan three.module.js disertakan dalam paket keluaran.

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

Saya membaca di suatu tempat bahwa contoh/js/* akan dihapus di beberapa titik. Akan lebih baik jika contoh jsm akan "berfungsi" sebelum itu.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

jack-jun picture jack-jun  ·  3Komentar

konijn picture konijn  ·  3Komentar

fuzihaofzh picture fuzihaofzh  ·  3Komentar

scrubs picture scrubs  ·  3Komentar

akshaysrin picture akshaysrin  ·  3Komentar