Three.js: يؤدي استيراد أمثلة من وحدات jsm إلى قيام الحزم بتجميع كود المصدر three.js مرتين

تم إنشاؤها على ١٢ سبتمبر ٢٠١٩  ·  43تعليقات  ·  مصدر: mrdoob/three.js

يؤدي الاستيراد من three/examples/jsm/.../<module> إلى أن تتضمن الحزم (التي تم اختبارها مع التجميع) المكتبة مرتين (أو عدة مرات).

على سبيل المثال ، عند تنفيذ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' ، سيتبع المجمع عملية الاستيراد وفي OrbitControls.js تأتي الواردات من ../../../build/three.module.js . ومع ذلك ، لا توجد طريقة للمجمع (الخارجي) لمعرفة أن ../../../build/three.module.js هو نفس الوحدة مثل three .

قد يكون حل هذا هو التعامل مع نماذج النماذج كحزم خارجية والاستيراد من three بدلاً من ../../../build/three.module.js . قد يؤدي هذا إلى كسر تكوين التجميع لـ three.js ، ولكن يجب أن يكون من الممكن إخبار التجميع بأن three هو اسم مستعار لنقطة الإدخال الرئيسية الثلاثة ( src/Three.js ).

التعليق الأكثر فائدة

أعتقد أنه مجرد شيء تعتاد عليه. الآن بعد أن أعتقد أنني فهمت الأمر ، فأنا على ما يرام مع ما هو عليه.

راجع للشغل لقد قمت بتحديث threejsfundamentals لتكون جميعها مبنية على esm 🤞

ال 43 كومينتر

(تم اختباره مع تراكمي)

لا أستطيع أن أؤكد هذا مع التراكمي. إذا كنت تفعل ذلك كما هو الحال في إعداد المشروع التالي ، فكل شيء يعمل كما هو متوقع.

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

إذا تعاملت مع three أنه تبعية خارجية:

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

ثم يجب ألا يحتوي الإخراج على الكود المصدري لـ three.js ، ومع ذلك فهو يتضمن كل شيء.

ومع ذلك ، إذا لم تقم باستيراد OrbitControls ، فسيشتمل الإخراج فقط على الكود المصدري لملف main.js .

يمكنك تجربتها من خلال التعليق على استيراد OrbitControls ، ثم إعادة البناء (ولكن باستخدام 'three' كاعتماد خارجي).

هذا مرتبط بـ # 17220 - أحد الحلول المقترحة هناك كان استبدال الحقل main في package.json بمسار بناء الوحدة ، لكن ذلك لن يصلح حالة الاستخدام هذه.

فقط لتوضيح المشكلة هنا هو أنه بينما يتم وضع علامة three أنها خارجية لإنشاء حزمة منفصلة تعتمد على ثلاثة في التكوين التراكمي الذي لا يمسك المرجع الثابت لـ ../../../build/three.module.js و يتضمنه في البناء. على سبيل المثال ، سيتضمن إنشاء الملف التالي عن غير قصد كود OrbitControls _ و_ كود threejs في الحزمة ، بالإضافة إلى استيراد نسخة أخرى من ثلاثة عند الإنشاء باستخدام التكوين المنشور @ 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 قد يكون من الجدير بالذكر أنه حتى إذا تم تغيير المسار في OrbitControls.js إلى three ستظل OrbitControls مضمنة في الحزمة الخاصة بك والتي قد تكون مرغوبة أو غير مرغوبة وقد ينتج عنها على الأقل يتم تضمين رمز OrbitControls مرتين في التطبيقات التابعة.

لا أقصد أن أقترح هذا كحل طويل الأجل أو أفضل حل ولكن تغيير التكوين لوضع علامة OrbitControls (وجميع الملفات الموجودة في المجلد الثلاثة) حيث أن ذلك خارجي من شأنه أن يحل هذا في كلتا الحالتين:

export default {
    // ...

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

    // ...
};

لا أقصد أن أقترح هذا كحل طويل الأجل أو أفضل حل ولكن تغيير التكوين لوضع علامة OrbitControls (وجميع الملفات في المجلد الثلاثة) على أنها خارجية ستحل هذا في كلتا الحالتين:

لسبب ما ، توقعت أن يعامل التجميع 'three/examples/jsm/controls/OrbitControls.js' أنه خارجي أيضًا بشكل افتراضي. لذا فإن الحل المقترح مناسب لحالة الاستخدام الخاصة بي.

الرقم 17220 ذو الصلة وثيق الصلة جدًا. ربما يجب أن تستمر المحادثة هناك.

إذن ماذا يحدث إذا فعلت هذا؟

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

ستنجح ، لكنها ليست مجدية ، لأن أي lib أو جزء من التعليمات البرمجية يعتمد على ثلاثة سوف يتم استيراده من "ثلاثة" ثم ينكسر مرة أخرى. يخبر Package.json البيئة عادةً بكيفية حل المشكلة ، "build / three.module" هو أحد تفاصيل التوزيع التي يجب ألا تتسرب. عندما يتم تخطي الدقة ، فإن ذلك يدعو فقط إلى حدوث مشكلات في مساحة الاسم.

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

gkjohnson ماذا لو أراد المستخدم تضمين المثال "الثلاثة" و OrbitControls في الحزمة؟

لست متأكدًا من أن الأمر مرتبط بحدوث مشابه إذا حاولت استخدام وحدات تعيش مثل هذا

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

يقوم بتحميل three.js مرتين ، مرة من CDN ومرة ​​أخرى من threejs.org

ربما ليست هذه هي الطريقة التي يُفترض أن تُستخدم بها الوحدات النمطية مع ثلاثة ، ولكن فقط من ما قبل 106 ، هناك آلاف المواقع والأمثلة التي تفعل ذلك

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

تُظهر جميع الأمثلة استخدام الوحدات النمطية مباشرة بدلاً من البناء (التجميع) ، بمعنى أنها لا تُظهر الطريقة الفعلية لاستخدام three.js كما اعتادوا. وبعبارة أخرى ، فإن الأمثلة القديمة خرجت من الصندوق. الأمثلة الجديدة لا AFAIK. لكي يعمل أحد الأمثلة ، ستحتاج إلى استخراج JavaScript من المثال ووضعه في ملف .js منفصل ، ثم وضع three.js محليًا (ربما عبر npm). أصلح جميع المسارات في الأمثلة بحيث تكون مسارات قائمة على الحزم (لا ../.././ البناء) ، وأخيراً استخدم التجميع

هذا تغيير كبير جدًا عن الإصدارات غير النمطية التي كان مجرد تغيير المسارات فيها كافيًا

تضمين التغريدة

مع التكوين الأصلي @ adrian-delgado ، سيتم تضمين three.js مرة واحدة وسيتم تضمين عناصر التحكم في المدار مرة واحدة ولن يتم تمييز أي حزم على أنها خارجية. مع التكوين الذي اقترحته ، سيكون هناك تبعية خارجية على three/build/three.module.js و three/examples/jsm/controls/OrbitControls.js في الحزمة المنتجة.

تضمين التغريدة

ماذا لو أراد المستخدم تضمين المثيل "ثلاثة" و OrbitControls في الحزمة؟

ثم يجب استبعاد الحقل external وفي هذه الحالة سيتم تضمين نسخة واحدة من ثلاثة عناصر تحكم في المدار في الحزمة. rollup-plugin-node-Resolution (وهو أمر ضروري للتجميع لدعم دقة الوحدة ويتم استخدامه في التكوينات أعلاه) الافتراضية لاستخدام حقل الوحدة من package.json (انظر الخيار mainFields ) وبالتالي فإن المدار يتحكم في ثلاثة مراجع و "ثلاثة" سيعمل على نفس البرنامج النصي. _If تم تغيير mainFields إلى ["main", "module"] لذلك تم استخدام "main" بدلاً من "module" في package.json_ فسيتم تضمين نسختين من ثلاثة هنا وستتعطل الأشياء بالطريقة التي تم بها ذكرنا سابقا. ومع ذلك فإنه يتطلب تغيير هذا المجال. ومع ذلك ، إذا تم استخدام "main" ، فمن المحتمل أن تكون هناك حاجة أيضًا إلى rollup-plugin-commonjs ، لأن التجميع لا يعرف كيفية معالجة ملفات Commonjs التي تتطلب بشكل افتراضي.

تضمين التغريدة

لسوء الحظ ، لا أعتقد أن الاستبدال الساذج للوحدات النمطية سيعمل بسهولة في هذه الحالة. لن يعالج أي من الحلول المقترحة هذه الحالة ولا أعتقد أن هناك أي شيء رسمي في الوقت الحالي يمكن استخدامه للمساعدة في حالة استيراد النص الأساسي والمثال من مضيفين منفصلين. خرائط الاستيراد هي الشيء الوحيد الذي يتم العمل عليه للمساعدة في ذلك على حد علمي. إذا تم استيراد المثال والثلاثة من نفس المضيف ، فسيتم تحميل نسخة واحدة فقط من ثلاثة:

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

اعتمادًا على حالة الاستخدام ، ربما يكون من الأفضل الاستمرار في استخدام علامات البرنامج النصي الكلاسيكية؟

تضمين التغريدة

لست متأكدًا من أن الأمر مرتبط بحدوث مشابه إذا حاولت استخدام وحدات تعيش مثل هذا

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

نعم ... لا تستخدم وحدات مثل هذه 😁

نعم ... لا تستخدم وحدات مثل هذه 😁

متفق. يمكن القول إن المستندات والأمثلة تستهدف في الغالب المطورين عديمي الخبرة وحقيقة أن أمثلة jsm هي الافتراضية ولن يعمل أي منهم بدون مُنشئ ولن يعمل عبر أي CDN هو نوع من التغيير الكبير.

كان من المعتاد أن تتمكن من عرض المصدر بشكل أساسي على مثال ، والنسخ واللصق في jsfiddle / codepen وما إلى ذلك ، وإصلاح المسارات في علامات البرنامج النصي وسيتم تشغيله. الآن على الرغم من أن جميع الأمثلة لن تعمل إلا إذا قمت بالارتباط مباشرة بموقع three.js ومشاهدتها تتعطل في كل مرة يتم فيها اصطدام الإصدار. (نعم ، أعلم أن الأمثلة غير النمطية موجودة ولكن هذه ليست الأمثلة المرتبطة من https://threejs.org/examples)

تضمين التغريدة

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

لا يعمل ، OrbitControls ليست على CDN والمسارات داخل OrbitContrls ../../../bulild/three.js ليست المسار الصحيح لجعلها تعمل

// أو

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

لا يعمل أيضًا لأنه سيتعطل في كل مرة تدفع فيها three.js إصدارًا جديدًا

ربما دفع مجلد أمثلة / js إلى CDN وثلاثة مثل أن مجرد إصلاح عناوين url في رمز المثال سيظل يعمل؟ هذا يعني أن three.module.js يجب أن يكون في

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

build إلى المسار

لذكر الخيارات ، تدعم شبكات CDN الأخرى مثل jsdelivr أو unpkg وحدات ES:

كان من المعتاد أن تتمكن بشكل أساسي من عرض المصدر على مثال ، والنسخ واللصق في jsfiddle / codepen وما إلى ذلك ، وإصلاح المسارات في علامات البرنامج النصي وسيتم تشغيله ...

أعتقد أننا سنحتاج إلى استيراد الخرائط لفعل أي شيء مفيد حيال ذلك ، للأفضل أو للأسوأ.

الآن على الرغم من أن جميع الأمثلة لن تعمل إلا إذا قمت بالربط مباشرة بموقع three.js

لن أشجع أي شخص على الارتباط مباشرة بالنصوص الحية على موقع threejs ... لن تكون هذه فكرة جيدة أبدًا. هناك بدائل ذات إصدار ، لكل تعليق أعلاه.

الوثائق التي من شأنها أن تجيب بشكل مثالي على هذه الأسئلة هي صفحة الاستيراد عبر الوحدات النمطية . هل هناك حالات يجب أن نغطيها هناك؟ أفترض أن ذكر شبكات CDN سيكون فكرة جيدة.

سيكون ذكر شبكات CDN فكرة جيدة. الإشارة أيضًا إلى أن Cloudflare CDN ، أول نتيجة ، على Google ليس جيدًا للوحدات النمطية (ما لم يتغير ذلك)

تضمين التغريدة

كان من المعتاد أن تتمكن من عرض المصدر بشكل أساسي على مثال ، والنسخ واللصق في jsfiddle / codepen وما إلى ذلك ، وإصلاح المسارات في علامات البرنامج النصي وسيتم تشغيله.

أنا بجانبك. أسوأ جزء من الوحدات هو أنه لا يمكنك الوصول إلى camera أو renderer من وحدة التحكم في الأمثلة بعد الآن 😟

ماذا لو بدأنا في استخدام unpkg؟

ماذا لو بدأنا في استخدام unpkg؟

هل تقصد البدء في استخدامه في الوثائق مثل صفحة الاستيراد عبر الوحدات النمطية ، أو استخدامه في المشروع بطريقة ما؟

أسوأ جزء من الوحدات النمطية هو أنه لا يمكنك الوصول إلى الكاميرا أو العارض من وحدة التحكم في الأمثلة بعد الآن

نعم ، هذا محبط. لقد قمت برمي هذا (أو ما شابه) في الأمثلة عند التطوير محليًا:

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

أفترض أن هذا شيء نأمل في حله باستخدام ملحق أدوات التطوير؟

فكرة واحدة قد تتطلب بعض البحث ، ولكنها قد تكون مثيرة للاهتمام ... إذا كنا على استعداد لإضافة خريطة استيراد polyfill لجميع الأمثلة ، أعتقد أنه يمكننا جعل الواردات المستخدمة هناك نسخ / لصق بنسبة 100٪ متوافقة مع npm- وتدفقات العمل القائمة على التجميع. على سبيل المثال:

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

ماذا لو بدأنا في استخدام unpkg؟

هل تقصد البدء في استخدامه في الوثائق مثل صفحة الاستيراد عبر الوحدات النمطية ، أو استخدامه في المشروع بطريقة ما؟

بدلاً من الإشارة إلى https://threejs.org/build/. نحن نستخدم هذا الرابط حاليًا في ISSUE_TEMPLATE .

ومن المحتمل أن ينتقلgreggman من https://cdnjs.cloudflare.com/ajax/libs/three.js/108/ إلى https://unpkg.com/[email protected]/ ؟

يبدو أن unpkg يحل المشكلات التي نناقشها هنا.

نعم ، هذا محبط. لقد قمت برمي هذا (أو ما شابه) في الأمثلة عند التطوير محليًا:

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

قرف! هاها

أفترض أن هذا شيء نأمل في حله باستخدام ملحق أدوات التطوير؟

نعم! 🤞

تضمين التغريدة

لست متأكدًا من أن الأمر مرتبط بحدوث مشابه إذا حاولت استخدام وحدات تعيش مثل هذا

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

نعم ... لا تستخدم وحدات مثل هذه 😁

لذلك وجدت نفسي اليوم أفعل ذلك بالضبط ... إنها عادة سيئة بالفعل ، لكن المشكلة هي أن معظم الأشياء تعمل نوعًا ما ولكن إذا حدث شيء ما يصعب حله.

في حالتي ، كنت أستورد three.module.js من dev و OBJLoader من master . OBJLoader المستوردة three.module.js من master حتى BufferGeometry لم يكن لديك جديدة usage الممتلكات ، و WebGLRenderer فعل لا تعرض الشبكة لأنها لم تعثر على usage ، كل شيء يعمل على الرغم من 😶

هذا شعر جميل ...

أعتقد أنه مجرد شيء تعتاد عليه. الآن بعد أن أعتقد أنني فهمت الأمر ، فأنا على ما يرام مع ما هو عليه.

راجع للشغل لقد قمت بتحديث threejsfundamentals لتكون جميعها مبنية على esm 🤞

يبدو أنه من الجيد أن يكون لديك three.module.min.js الرغم من (أو أن three.min.module.js 😜)

+1

أقوم فقط باستيراد ثلاثة عناصر تحكم في المدار كوحدات ES6 ولأن عناصر التحكم في المدار (على ما يبدو) تشير إلى ثلاثة داخل مجلد الإنشاء ، فقد استغرق الأمر بعض الوقت لمعرفة مساراتي

معجب كبير يمكننا استخدام ثلاث وحدات ، ولكن سيكون من الجيد أن يكون لدينا المزيد من المرونة حول هذا ، لن أخوض في ملف عناصر التحكم في المدار وأبدأ العبث ، على افتراض أن هذا هو الحال مع الوحدات الأخرى أيضًا.

أيضًا +1 لمدة ثلاثة دقائق

الانتقال من # 18239، حصلت على واقعة في ذلك مشكلة مماثلة عن طريق القيام npm link على حزمة أخرى أن الاستخدامات three.js.

لقد قمت بتطوير مكون إضافي مكون من ثلاثة مصغرة والذي قد يساعد في حل هذه المشكلة.

أواجه نفس المشكلة. أكتب مكون React باستخدام three.js ، وأقوم باستيراد بعض الوحدات من الأمثلة. بمجرد أن يتم تجميعها مع التجميع ، إذا نظرت إلى الحزمة ، يمكنني أن أرى أن هناك بيان استيراد واحد لثلاثة ، ثم رمز Three.js.

إذا استخدمت بيان الاستيراد هذا في المكون الخاص بي: import * as THREE from "three/build/three.module"
تعمل الأشياء بشكل صحيح ولكن يتم تضمين ثلاثة في الحزمة ، وهو شيء لا أريده.
أود الحصول على بيان استيراد لثلاثة أشخاص. إذا استخدمت import * as THREE from "three ، فسيتم استيراد ثلاثة للحزمة كوحدة نمطية ، ولكن بمجرد استخدام أحد الأمثلة ، تتم إضافة three.js في الحزمة (= لدي بيان استيراد واحد لثلاثة ، ثم رمز الثلاثة) ، مما يؤدي في النهاية إلى تعطل الكود الخاص بي

تضمين التغريدة

أكتب مكون React باستخدام three.js ، وأقوم باستيراد بعض الوحدات من الأمثلة. بمجرد أن يتم تجميعها مع التجميع ، إذا نظرت إلى الحزمة ، يمكنني أن أرى أن هناك بيان استيراد واحد لثلاثة ، ثم رمز Three.js.

يجب أن يحل الحل المنشور هنا مشكلتك: https://github.com/mrdoob/three.js/issues/17482#issuecomment -530957570.

أشعر أن الكثير من هذه المشكلات مستمدة من الأشخاص الذين لا يفهمون تمامًا ما يحدث مع أداة التجميع الخاصة بهم (وهو أمر مفهوم) ولكن هذه المشكلات ليست فريدة من نوعها بالنسبة لثلاثة أشخاص. من الممكن ، على الرغم من ذلك ، أن يكون الاستيراد المزدوج بطريق الخطأ للنواة الثلاثة أكثر وضوحًا من المكتبات الأخرى. يمكن بسهولة تفويت تجميع تبعية يُقصد بها أن تكون خارجية مثل لوداش أو مكون تفاعل أو OrbitControls.

فيما يتعلق بالاعتماد على حزمة خارجية ، يوثق Rollup هذا السلوك ويوفر خيارًا هنا ولدى Webpack خيار مماثل هنا . في هذه الحالة ، إذا كانت ملفات الأمثلة تشير بدلاً من ذلك إلى "ثلاثة" ، فبينما لن يتم تجميع المكتبة الأساسية ، لا يزال بإمكانك الحصول على حزم مكررة من أمثلة التعليمات البرمجية التي تمثل مشكلتها الخاصة. ولا أعتقد أن هناك أي شيء يمكن أن يفعله هذا المشروع لمساعدة الحزم في تفسير عيوب ارتباط npm. أعتقد أن الحالة الإشكالية الوحيدة التي رأيتها وأشعر أنها ليست نتيجة لمجمع تم تكوينه بشكل خاطئ هي حالة codeandbox.

بالنسبة لحالات التجميع ، ربما تكون الإجابة هي التوثيق أو إضافة دليل استكشاف الأخطاء وإصلاحها أو الارتباط بكيفية تكوين الحزم الشائعة في صفحة الاستيراد عبر الوحدات النمطية .

لدي حدس مفاده أنه إذا كان بإمكان حزم examples/jsm تغيير هذا النمط ...

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

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

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

... سيكون حل هذه المشكلات أسهل بكثير. لسوء الحظ ، لا أعرف كيف يمكننا إدارة أمثلة HTML داخل موقع الويب threejs دون إعداد بناء معقد بعد ذلك. قد يحلها مخطط الاستيراد polyfill على موقع threejs ، لكنني لست متأكدًا. : /

إذا كانت ملفات الأمثلة تشير بدلاً من ذلك إلى "ثلاثة" ، فبينما لن يتم تجميع المكتبة الأساسية ، ستظل تحصل على حزم مكررة من أمثلة التعليمات البرمجية ...

أنا لا أتابع هذا تمامًا. لأنها عمليات استيراد مسار نسبي؟ يمكننا أن نجعلها مرتبطة بالحزمة.

تضمين التغريدة

لدي حدس مفاده أنه إذا كان بإمكان أمثلة / حزم jsm تغيير هذا النمط ... فسيكون حل هذه المشكلات أسهل بكثير.

أعتقد أن هذا سيجعل الأمر يبدو محلاً ، لكن سيظل لدى الأشخاص رمز مكرر يصعب ملاحظته لأنه لا يتسبب في تعطل التطبيق.

أنا لا أتابع هذا تمامًا. لأنها عمليات استيراد مسار نسبي؟ يمكننا أن نجعلها مرتبطة بالحزمة.

آسف إذا كنت غير واضح أعتقد أن هذا صعب بعض الشيء في التوضيح - آمل أن يكون هذا أكثر وضوحًا. سأستخدم حالة Rollup:

في الحالات المذكورة أعلاه ، حيث يرغب الأشخاص في تجميع حزمة بعلامة three أنها خارجية ، أفترض أنهم يقومون ببناء مكتبة حيث سيكون three.js تبعية للأقران يمكن أن يعتمد عليها تطبيق آخر:

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

سيكون الهدف هنا هو بقاء عمليات الاستيراد الثلاثة السابقة في المكتبة وتحميل الحزمة ثلاثة و OrbitControls كتبعيات نظير ، لذلك إذا كان التطبيق يستخدم أيضًا three.js و OrbitControls ، فلن تستورد مرتين.

يتوقع الناس الخيار external: [ 'three' ] لتحقيق هذا السلوك بالنسبة لهم (لقد فعلت ذلك بالتأكيد) ولكن هذا لا يحدث لأن السلسلة لا تتطابق مع مسار الاستيراد OrbitControls. ينتج عن هذا تجميع OrbitControls قصد ، وبالتالي يتم تجميع ../../../build/three.module.js أيضًا (لأنه لا يتطابق أيضًا مع السلسلة). أعتقد أن الأشخاص يشيرون إلى أن الملف الأساسي three.js يتم تجميعه لأنه أكثر وضوحًا - تعطل التطبيقات ، وحزمة المكتبة أكبر بكثير ، وما إلى ذلك - حيث الحقيقة هي أن ملف OrbitControls لا يجب أن يتم تجميعه في المركز الأول. الطريقة الصحيحة لتكوين التراكمية هنا هي ضبط الخيار على external: path => /^three/.test( path ) .

هذا ليس فريدًا بالنسبة لثلاثة أشخاص. يستخدم Rollup مستنداته ، لكن سيكون من الصعب / من المستحيل ملاحظة ما إذا كان 'lodash/merge' تجميعه في رمز مكتبتك لأنه صغير جدًا ولن يتسبب في أخطاء استيراد مكررة. تشجع واجهة المستخدم المادية مراجع الملفات المتداخلة في عمليات الاستيراد وبالمثل سيفشل الإعداد external: ['@material-ui/core'] في استبعاد '@material-ui/core/Button' من الحزمة.

لا أعتقد أنه من المجدي تغيير رمز المثال لحالات الاستخدام هذه لأنه سيظل يؤدي إلى رمز مكرر لن يكون موجودًا إذا تم تكوين المجمّع بشكل صحيح.

حالتان هنا:

(1) يريد المستخدم threejs والأمثلة مدرجة مرة واحدة ، ويحصل على شيء مرتين

على سبيل المثال أثناء إنشاء التطبيق.

(2) يريد المستخدم threejs والأمثلة متضمنة صفر مرة ، يحصل على شيء 1+ مرة

على سبيل المثال ، أثناء بناء مكتبة بها ثلاثة تبعية خارجية أو تبعية نظير.


على حد علمي ، لا يزال كل من (1) و (2) من المشكلات التي يسهل التعثر فيها؟ إذا كان النهج أعلاه يحل (1) ، فهذا وحده مفيد. لست متأكدًا بشأن (2). ربما يجب ذكر خدعة /^three/.test( path ) عند الاستيراد عبر الوحدات ؟

gkjohnson شكرًا على هذا الشرح ، لقد ساعدني حقًا في توضيح أفكاري

في تكوين التجميع الخاص بي ، كنت أقوم بتعريف external بهذه الطريقة

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

اعتقدت أنها ستنجح ، حيث سيتم التعامل مع ثلاثة على أنها تبعيات خارجية ؛ ولكن كما ذكرت ، يجب عليك استخدام regex (بقدر ما أفهم ، أعتقد أن السبب هو أن الأمثلة تفعل
import from "../../../build/three.module.js"; ). لذلك انتهى بي الأمر

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

إنه سؤال غير ذي صلة إلى حد ما ، لكنني أتوقع أن جميع التبعيات التي أعلنت عنها في package.json ليست جزءًا من الحزمة؟ هل هو افتراض صحيح؟

تضمين التغريدة

على حد علمي ، لا يزال كل من (1) و (2) من المشكلات التي يسهل التعثر فيها؟

في رأيي (2) هو نتيجة تكوين المجمّع بشكل غير صحيح وربما يمكننا معالجة ذلك عن طريق تحديث المستندات ببعض الاقتراحات للحزم. (1) يمكن أن يحدث نتيجة لاستخدام حزمة تعاني من مشكلة (2) ولكن بخلاف ذلك لست مقتنعًا (1) من السهل التعثر عليها. أرغب في رؤية حالة استخدام في العالم الحقيقي توضح المشكلة لمعرفة كيفية قيام شخص ما بتكوين أداة التجميع الخاصة به ولكن إليك قائمة بالطرق التي أعرف أنه يمكنك الوصول إليها (حتى الآن):

  1. استيراد صريح من 'three/src/Three.js' أو 'three/build/three.min.js' (وهو أمر غير موصى به في المستندات).
  2. أعد تكوين المجمّع لاستخدام الحقل package.main بدلاً من الحقل package.module عند الحل. تفضل جميع المجمعات الثلاثة الكبيرة Rollup و Webpack و Parcel جميعًا module على main بشكل افتراضي. تبدو حالة الاستخدام هذه وكأنها غير شائعة ولكن هذا مجرد افتراض.
  3. استخدم npm link لتضمين حزمة ذات ارتباط رمزي تعتمد على ثلاثة (تم إصلاح ذلك باستخدام خيار التجميع preserveSymlinks )
  4. استخدم ثلاثة أمثلة في codeandbox.io لأن النظام الأساسي يعطي الأولوية للحقل الرئيسي على الوحدة النمطية .

يبدو أن الرقم 4 هو الوحيد الذي يمكن العثور عليه بسهولة ، على الرغم من أنني أعلم أن الناس يفعلون 1 من أجل هز الشجرة. يشعر الآخرون أنهم خارج سيطرتنا أو أنهم سيكونون غير مألوفين للغاية.

تضمين التغريدة

بقدر ما أفهم ، أعتقد أن ذلك لأن الأمثلة تفعل import from "../../../build/three.module.js"; ...

ليس هذا هو الحال ، يرجى قراءة ما شرحته هنا: https://github.com/mrdoob/three.js/issues/17482#issuecomment -583694493. /^three لأنه يطابق السلسلة 'three/examples/jsm/controls/OrbitControls.js' والتي يجب أن تكون أيضًا خارجية لأنها جزء من مكتبة three.js بينما السلسلة 'three' لا تفعل ذلك. يمكن أن يحدث الشيء نفسه مع التبعيات الأخرى أيضًا. أوصي باستخدام regex لجميع التبعيات لتجنب المزالق الأخرى غير المعروفة أو المطابقة مع أي حزمة ذات محدد وحدة عارية.

gkjohnson شكرًا على الشرح التفصيلي ، هذا منطقي بالنسبة لي.

يبدو أن هذا لا يحل المشكلة في هذا الموضوع بعد كل شيء ، ولكن نظرًا لأنني أشرت إليها بالفعل عدة مرات في السلسلة ، فقد اختبرت أخيرًا خريطة استيراد polyfill: https://github.com/KhronosGroup/ برنامج KTX / سحب / 172 / ملفات. باستخدام هذا polyfill ، يعمل import * as THREE from 'three'; في متصفح الويب.

إذا أظهر المتصفح بعض الثقة فقط ...
https://github.com/WICG/import-maps/issues/212#issuecomment -663564421

لقد واجهت نفس المشكلة عند إضافة فئة مرور فرعية إلى أحد مشاريعي

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

ونظرًا لأنني فضلت نسخ رمز المرور في الوحدة النمطية الخاصة بي ، حتى لا أضطر إلى استيراده لاحقًا من three.js على المتصفح ، فقد تقدمت في العثور على حل بديل:

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

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

بهذه الطريقة ، تعمل مع المتصفحات ، ويجب أن تعمل عمليات استيراد الوحدات أيضًا.

تحرير :

سيؤدي التحميل من مشروع محلي ثلاثي (انظر المثال أدناه) إلى كسر هذا النهج ويتطلب بعض الحلول الإضافية.

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

حسنًا ، لقد تقدمت وأنشأت إصدارًا جديدًا يدعم الارتباط المحلي:

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 تمت معالجة هذا أعلاه في https://github.com/mrdoob/three.js/issues/17482#issuecomment -530957570. إذا كنت تستخدم Rollup وترغب في وضع علامة three.js على أنها خارجية عند استخدام نماذج الوحدات النمطية ، عليك القيام بما يلي على النحو المقترح:

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

ليس هناك سبب لجعل التكوين معقدًا للغاية. سيضمن هذا وضع علامة على كل من ملف Pass.js ووحدة three.js كملف خارجي.

gkjohnson حالة الاستخدام الخاصة بي ليست هي نفسها تمامًا ، لأنني أريد فقط تمييز three lib على أنه خارجي ، وليس المثال (أريد أن يتم تجميع المثال مع الإصدار الخاص بي).

أنا أقوم ببناء مكتبة بها ثلاثة كمثال خارجي ، وأريد أن يتم تجميع المثال في عرض البنية ولكن بدون ثلاثة ، وكما تمت مناقشته أعلاه ، عند استيراد وحدة من الأمثلة ، سيحتوي الإخراج على رمز ثلاثة. هل من الممكن تحقيقه مع webpack؟

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

Mcgoderecardinal لا أعتقد أن ذلك ممكن. أردت أن أفعل الشيء نفسه لذلك قمت فقط بنسخ / لصق الكود من الأمثلة ؛ في حالتي كان علي "تعديل" الواردات والصادرات وكان هذا كل شيء. من الواضح أن هذا ليس مثاليًا ولكنه كان جيدًا بما يكفي لحالة الاستخدام الخاصة بي.

لدي حالة استخدام مماثلة هنا مع Webpack و THREE باعتبارها خارجية. تؤدي عمليات الاستيراد التالية إلى تضمين three.module.js في الإخراج المجمّع.

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

قرأت في مكان ما أن الأمثلة / js / * ستتم إزالتها في مرحلة ما. سيكون من الجيد لو أن أمثلة jsm "تعمل فقط" قبل ذلك الحين.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

kumavis picture kumavis  ·  153تعليقات

arefin86 picture arefin86  ·  64تعليقات

mrdoob picture mrdoob  ·  66تعليقات

RicoLiu picture RicoLiu  ·  100تعليقات

lmcd picture lmcd  ·  74تعليقات