RequireJS 2.3

RequireJS API




requirejs

استعمال

تحميل ملفات جافا سكريبت

يأخذ RequireJS أسلوبًا مختلفًا لتحميل البرنامج النصي من العلامات <script> التقليدية. في حين أنه يمكن أيضًا تشغيله بسرعة وتحسينه بشكل جيد ، فإن الهدف الأساسي هو تشجيع الشفرة المعيارية. كجزء من ذلك ، يشجع استخدام المعرفات النمطية بدلاً من عناوين URL لعلامات البرنامج النصي.

RequireJS بتحميل كافة التعليمات البرمجية المتعلقة baseUrl . يتم تعيين baseUrl عادة على نفس الدليل كالنص البرمجي المستخدم في سمة البيانات الرئيسية للنص البرمجي ذي المستوى الأعلى الذي يتم تحميله للصفحة. السمة الرئيسية للبيانات هي سمة خاصة ستتطلب check.js بدء تحميل البرنامج النصي. سوف ينتهي هذا المثال مع baseUrl من البرامج النصية :

<!--This sets the baseUrl to the "scripts" directory, and
    loads a script that will have a module ID of 'main'-->
<script data-main="scripts/main.js" src="scripts/require.js"></script>

أو ، يمكن تعيين baseUrl يدوياً عن طريق تكوين RequireJS . إذا لم يكن هناك تكوين صريح ولا يتم استخدام البيانات الرئيسية ، فإن baseUrl الافتراضي هو الدليل الذي يحتوي على صفحة HTML قيد التشغيل RequireJS.

يفترض أيضًا RequireJS بشكل افتراضي أن كافة التبعيات هي برامج نصية ، لذلك لا يتوقع أن ترى لاحقة ".js" لاحقة على معرفات الوحدة النمطية. سيقوم RequireJS تلقائيًا بإضافته عند ترجمة معرف الوحدة إلى مسار. باستخدام تكوين المسارات ، يمكنك إعداد مواقع مجموعة من النصوص البرمجية. تسمح لك كل هذه الإمكانيات باستخدام سلاسل صغيرة للنصوص مقارنةً بالعلامات <script> التقليدية.

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

  • ينتهي في ".js".
  • يبدأ بـ "/".
  • يحتوي على بروتوكول URL ، مثل "http:" أو "https:".

بشكل عام على الرغم من ذلك ، من الأفضل استخدام التكوين baseUrl و "المسارات" لتعيين مسارات لمعرفات الوحدة النمطية. من خلال القيام بذلك ، فإنه يمنحك المزيد من المرونة في إعادة تسمية وتكوين المسارات إلى مواقع مختلفة للبناء الأمثل.

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

  • شبكة الاتصالات العالمية /
    • index.html و
    • شبيبة /
      • التطبيق /
        • sub.js
      • ليب /
        • jquery.js
        • canvas.js
      • app.js
      • require.js

في index.html:

<script data-main="js/app.js" src="js/require.js"></script>

وفي app.js:

requirejs.config({
    //By default load any module IDs from js/lib
    baseUrl: 'js/lib',
    //except, if the module ID starts with "app",
    //load it from the js/app directory. paths
    //config is relative to the baseUrl, and
    //never includes a ".js" extension since
    //the paths config could be for a directory.
    paths: {
        app: '../app'
    }
});

// Start the main app logic.
requirejs(['jquery', 'canvas', 'app/sub'],
function   ($,        canvas,   sub) {
    //jQuery, canvas and the app/sub module are all
    //loaded and can be used here now.
});

لاحظ أنه كجزء من هذا المثال ، لم يكن لدى مكتبات الموردين مثل jQuery أرقام إصداراتها في أسماء الملفات الخاصة بها. من المستحسن تخزين معلومات الإصدار هذه في ملف نصي منفصل إذا كنت ترغب في تتبعها ، أو إذا كنت تستخدم أداة مثل volo ، فسيتم ختم package.json بمعلومات الإصدار مع الاحتفاظ بالملف على القرص كـ "jquery". شبيبة ". يتيح لك هذا الحصول على الحد الأدنى من التكوين بدلاً من وضع إدخال في تكوين "المسارات" لكل مكتبة. على سبيل المثال ، تكوين "jquery" لتكون "jquery-1.7.2".

من الناحية المثالية ، ستكون البرامج النصية التي تقوم بتحميلها وحدات يتم تعريفها بواسطة استدعاء define () . ومع ذلك ، قد تحتاج إلى استخدام بعض البرامج النصية "globals المستعرضات" التقليدية / القديمة التي لا تعبر عن التبعيات الخاصة بهم عبر تعريف (). لتلك ، يمكنك استخدام التكوين الرقاقة . للتعبير عن الاعتمادية بشكل صحيح.

إذا لم تقم بالتعبير عن التبعيات ، فمن المحتمل أن تحصل على أخطاء في التحميل لأن RequireJS يقوم بتحميل البرامج النصية بشكل غير متزامن وخارج الترتيب للسرعة.

data-main Entry Point

السمة الرئيسية للبيانات هي سمة خاصة ستتطلب check.js بدء تحميل البرنامج النصي:

<!--when require.js loads it will inject another script tag
    (with async attribute) for scripts/main.js-->
<script data-main="scripts/main" src="scripts/require.js"></script>

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

على سبيل المثال ، سوف يفشل هذا الترتيب بشكل عشوائي عندما لا يتم تعيين المسار require.config لوحدة "foo" قبل أن يتطلب الأمر () في وقت لاحق:

<script data-main="scripts/main" src="scripts/require.js"></script>
<script src="scripts/other.js"></script>
// contents of main.js:
require.config({
    paths: {
        foo: 'libs/foo-1.1.3'
    }
});
// contents of other.js:

// This code might be called before the require.config() in main.js
// has executed. When that happens, require.js will attempt to
// load 'scripts/foo.js' instead of 'scripts/libs/foo-1.1.3.js'
require(['foo'], function(foo) {

});

إذا كنت تريد require() مكالمات require() في صفحة HTML ، فمن الأفضل عدم استخدام البيانات الرئيسية. يتم استخدام البيانات الرئيسية فقط للاستخدام عندما يكون للصفحة نقطة دخول رئيسية واحدة فقط ، وهي البرنامج النصي الرئيسي للبيانات. بالنسبة للصفحات التي تريد إجراء مضمن require() ، من الأفضل تضمين تلك الموجودة داخل استدعاء require() للتهيئة:

<script src="scripts/require.js"></script>
<script>
require(['scripts/config'], function() {
    // Configuration loaded now, safe to do other require calls
    // that depend on that config.
    require(['foo'], function(foo) {

    });
});
</script>

تحديد وحدة نمطية

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

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

(إذا كنت معتادًا على وحدات CommonJS أو تستخدمها ، فالرجاء أيضًا الاطلاع على CommonJS Notes للاطلاع على معلومات حول كيفية تعيين تنسيق الوحدة النمطية RequireJS إلى وحدات CommonJS).

يجب أن يكون هناك فقط تعريف وحدة واحدة لكل ملف على القرص. يمكن تجميع الوحدات في حزم محسّنة باستخدام أداة التحسين .

أزواج اسم / قيمة بسيطة

إذا لم يكن لدى الوحدة أي تبعيات ، وأنها مجرد مجموعة من أزواج الاسم / القيمة ، ثم مجرد تمرير كائن حرفي لتعريف ():

//Inside file my/shirt.js:
define({
    color: "black",
    size: "unisize"
});

وظائف التعريف

إذا كانت الوحدة لا تحتوي على تبعيات ، ولكن تحتاج إلى استخدام وظيفة للقيام ببعض أعمال الإعداد ، ثم تعريف نفسها ، وتمرير وظيفة لتعريف ():

//my/shirt.js now does setup work
//before returning its module definition.
define(function () {
    //Do setup work here

    return {
        color: "black",
        size: "unisize"
    }
});

تعريف وظائف مع التبعيات

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

//my/shirt.js now has some dependencies, a cart and inventory
//module in the same directory as shirt.js
define(["./cart", "./inventory"], function(cart, inventory) {
        //return an object to define the "my/shirt" module.
        return {
            color: "blue",
            size: "large",
            addToCart: function() {
                inventory.decrement(this);
                cart.add(this);
            }
        }
    }
);

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

  • بلدي / cart.js
  • بلدي / inventory.js
  • بلدي / shirt.js

تحدد استدعاء الدالة أعلاه وسيطتين ، هما "cart" و "inventory". هذه هي الوحدات النمطية التي تمثلها "./cart" و "./inventory" أسماء الوحدة النمطية.

لا يتم استدعاء الدالة حتى يتم تحميل وحدات / cart و / المخزون الخاص بي ، وتتلقى الدالة الوحدات كوسيط "العربة" و "المخزون".

يتم بشكل صريح تثبيط الوحدات النمطية التي تحدد globals ، بحيث يمكن أن توجد إصدارات متعددة من وحدة نمطية في صفحة في كل مرة (انظر الاستخدام المتقدم ). أيضاً ، يجب أن يتطابق ترتيب وسائط الدالة مع ترتيب التبعيات.

يحدد الكائن المرجع من استدعاء الدالة الوحدة النمطية "my / shirt". من خلال تعريف الوحدات بهذه الطريقة ، لا يوجد "my / shirt" ككائن عالمي.

تحديد وحدة نمطية كوظيفة

الوحدات النمطية لا يلزم إرجاع الكائنات. يُسمح بأي قيمة إرجاع صالحة من إحدى الوظائف. في ما يلي وحدة نمطية تقوم بإرجاع دالة على أنها تعريف الوحدة النمطية لها:

//A module definition inside foo/title.js. It uses
//my/cart and my/inventory modules from before,
//but since foo/title.js is in a different directory than
//the "my" modules, it uses the "my" in the module dependency
//name to find them. The "my" part of the name can be mapped
//to any directory, but by default, it is assumed to be a
//sibling to the "foo" directory.
define(["my/cart", "my/inventory"],
    function(cart, inventory) {
        //return a function to define "foo/title".
        //It gets or sets the window title.
        return function(title) {
            return title ? (window.title = title) :
                   inventory.storeName + ' ' + cart.name;
        }
    }
);

تحديد وحدة نمطية باستخدام Simplified CommonJS Wrapper

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

define(function(require, exports, module) {
        var a = require('a'),
            b = require('b');

        //Return the module value
        return function () {};
    }
);

يعتمد هذا المجمّع على Function.prototype.toString () لإعطاء قيمة سلسلة مفيدة لمحتويات الدالة. لا يعمل هذا على بعض الأجهزة مثل PS3 وبعض متصفحات Mobile Opera القديمة. استخدم المحسن لسحب التبعيات في تنسيق الصفيف للاستخدام على هذه الأجهزة.

يتوفر المزيد من المعلومات على صفحة CommonJS ، وفي قسم "Sugar" في صفحة Why AMD .

تعريف وحدة نمطية باسم

قد تصادف بعض المكالمات التعريفية () التي تتضمن اسمًا للوحدة النمطية باعتبارها أول وسيطة لتعريف ():

    //Explicitly defines the "foo/title" module:
    define("foo/title",
        ["my/cart", "my/inventory"],
        function(cart, inventory) {
            //Define foo/title object in here.
       }
    );

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

ملاحظات الوحدة النمطية الأخرى

وحدة واحدة لكل ملف. : يجب تعريف وحدة واحدة فقط لكل ملف JavaScript ، نظراً لطبيعة خوارزمية البحث عن اسم ملف إلى ملف مسار. لا تستخدم إلا أداة التحسين لتجميع وحدات متعددة في ملفات محسّنة.

أسماء النطاقات النسبية داخل تعريف () : للمطالبة ("./ النسبية / الاسم") التي يمكن أن تحدث داخل استدعاء دالة التعريف () ، تأكد من أن تطلب "تتطلب" كتبعية ، بحيث يتم حل الاسم النسبي بشكل صحيح:

define(["require", "./relative/name"], function(require) {
    var mod = require("./relative/name");
});

أو الأفضل من ذلك ، استخدم بناء الجملة المختصر المتاح للاستخدام مع ترجمة وحدات CommonJS :

define(function(require) {
    var mod = require("./relative/name");
});

يستخدم هذا النموذج Function.prototype.toString () للبحث عن استدعاءات () ، وإضافتها إلى مصفوفة التبعية ، مع "يتطلب" ، بحيث تعمل الشفرة بشكل صحيح مع المسارات النسبية.

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

ترتبط أسماء الوحدات النمطية النسبية بالأسماء الأخرى ، وليس المسارات : يخزن اللودر الوحدات النمطية حسب أسمائهم وليس بمسارها داخليًا. لذلك بالنسبة لمراجع الاسم النسبي ، يتم حلها بالنسبة إلى اسم الوحدة النمطية الذي يجعل المرجع ، ثم يتم تحويل اسم الوحدة النمطية ، أو المعرف ، إلى مسار إذا كان يلزم تحميله. رمز مثال لحزمة 'compute' التي تحتوي على وحدات نمطية 'main' و 'extras':

* lib/
    * compute/
        * main.js
        * extras.js

حيث تبدو الوحدة main.js بالشكل التالي:

define(["./extras"], function(extras) {
    //Uses extras in here.
});

إذا كان هذا هو تكوين المسارات:

require.config({
    baseUrl: 'lib',
    paths: {
      'compute': 'compute/main'
    }
});

وهناك حاجة require(['compute']) تتم ، فإن lib / compute / main.js سيكون لها اسم الوحدة' compute '. عندما يسأل عن "./extras" ، يتم حل ذلك بالنسبة إلى "compute" ، لذلك "compute /./ extras" ، والتي تطبع إلى "إضافات" فقط. نظرًا لعدم وجود تكوين مسارات لاسم الوحدة النمطية هذا ، فسيكون المسار الذي تم إنشاؤه هو 'lib / extras.js' ، وهو غير صحيح.

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

خيار آخر هو بناء وحدة نمطية في lib / compute.js التي define(['./compute/main'], function(m) { return m; }); فقط define(['./compute/main'], function(m) { return m; }); ، ثم ليست هناك حاجة لتكوينات المسارات أو الحزم.

أو لا تقم بتعيين إعدادات المسارات أو الحزم والقيام بالمستوى الأعلى تتطلب الاتصال كما هو require(['compute/main']) .

إنشاء عناوين URL ذات صلة بالوحدة : قد تحتاج إلى إنشاء عنوان URL متعلق بوحدة نمطية. للقيام بذلك ، اطلب "مطلوب" كاعتمادية ثم استخدم require.toUrl () لإنشاء عنوان URL:

define(["require"], function(require) {
    var cssUrl = require.toUrl("./style.css");
});

تصحيح الأخطاء في وحدة التحكم : إذا كنت بحاجة إلى العمل بوحدة نمطية تم تحميلها بالفعل عبر require(["module/name"], function(){}) استدعاء require(["module/name"], function(){}) في وحدة تحكم جافا سكريبت ، يمكنك استخدام النموذج () الذي يتطلب اسم سلسلة الوحدة النمطية لجلبه:

require("module/name").callSomeFunction()

لاحظ أن هذا يعمل فقط إذا كان "module / name" قد تم تحميله مسبقًا عن طريق الإصدار المتزامن المطلوب: require(["module/name"]) . إذا كنت تستخدم مسارًا نسبيًا ، مثل "./module/name" ، فسيعرف ذلك فقط داخل العمل

التبعية التعميمية

إذا قمت بتعريف تبعية دائرية ("a" يحتاج إلى "b" و "b" يحتاج "a") ، ففي هذه الحالة عندما يتم استدعاء دالة الوحدة النمطية "b" ، ستحصل على قيمة غير محددة لـ "a". يمكن لـ "b" إحضار "a" لاحقًا بعد تحديد الوحدات النمطية باستخدام الطريقة required () (تأكد من تحديد الحاجة باعتبارها تبعًا لذلك يتم استخدام السياق الصحيح للبحث عن "a"):

//Inside b.js:
define(["require", "a"],
    function(require, a) {
        //"a" in this case will be null if "a" also asked for "b",
        //a circular dependency.
        return function(title) {
            return require("a").doSomething();
        }
    }
);

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

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

//Inside b.js:
define(function(require, exports, module) {
    //If "a" has used exports, then we have a real
    //object reference here. However, we cannot use
    //any of "a"'s properties until after "b" returns a value.
    var a = require("a");

    exports.foo = function () {
        return a.bar();
    };
});

أو ، إذا كنت تستخدم نهج مصفوفة التبعية ، فاطلب التبعية الخاصة "بالصادرات":

//Inside b.js:
define(['a', 'exports'], function(a, exports) {
    //If "a" has used exports, then we have a real
    //object reference here. However, we cannot use
    //any of "a"'s properties until after "b" returns a value.

    exports.foo = function () {
        return a.bar();
    };
});

حدد تبعية خدمة JSONP

JSONP هي طريقة للاتصال ببعض الخدمات في JavaScript. وهو يعمل عبر النطاقات وهو أسلوب ثابت للاتصال بالخدمات التي تتطلب فقط HTTP GET عبر علامة نصي.

لاستخدام خدمة JSONP في RequireJS ، حدد "define" كقيمة معلمة معاودة الاتصال. هذا يعني أنه يمكنك الحصول على قيمة عنوان JSONP URL كما لو كان تعريف وحدة نمطية.

في ما يلي مثال يستدعي نقطة نهاية JSONP API. في هذا المثال ، تُسمى معلمة رد الاتصال JSONP "callback" ، لذلك "callback = define" تخبر واجهة برمجة التطبيقات بتغليف استجابة JSON في التفاف "define ()":

require(["http://example.com/api/data.json?callback=define"],
    function (data) {
        //The data object will be the API response for the
        //JSONP data call.
        console.log(data);
    }
);

يجب أن يقتصر استخدام JSONP على خدمات JSONP لإعداد التطبيق الأولي. إذا انتهت مهلة خدمة JSONP ، فهذا يعني أن الوحدات الأخرى التي تحددها من خلال define () قد لا يتم تنفيذها ، وبالتالي فإن معالجة الأخطاء ليست قوية.

يتم دعم قيم الإرجاع فقط JSONP التي هي كائنات JSON . لن تعمل استجابة JSONP وهي صفيف أو سلسلة أو رقم.

يجب عدم استخدام هذه الوظيفة لاتصالات JSONP طويلة الاستقصاء - واجهات برمجة التطبيقات التي تتعامل مع البث المباشر في الوقت الفعلي. يجب على هذه الأنواع من واجهات برمجة التطبيقات إجراء المزيد من عمليات تنظيف البرامج النصية بعد تلقي كل استجابة ، وسيجلب RequireJS فقط عنوان URL لـ JSONP مرة واحدة - سيحصل الاستخدام اللاحق لنفس عنوان URL كعنصر اتصال مطلوب () أو تعريف () على قيمة مخزنة مؤقتًا.

تظهر الأخطاء في تحميل خدمة JSONP عادةً عبر المهلات للخدمة ، نظرًا لأن تحميل علامة البرنامج النصي لا يعطي الكثير من التفاصيل في مشكلات الشبكة. للكشف عن الأخطاء ، يمكنك تجاوز requiredjs.onError () للحصول على أخطاء. هناك المزيد من المعلومات في قسم معالجة الأخطاء .

تعريف الوحدة

هناك دالة عالمية ، requirejs.undef () ، تسمح بتعريف الوحدة. سيقوم بإعادة ضبط الحالة الداخلية لوادر المشغل لنسيان التعريف السابق للوحدة.

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

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

علم الميكانيكا

يحمّل RequireJS كل تبعية كعلامة نصي ، باستخدام head.appendChild ().

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

استخدام RequireJS في بيئة جافا سكريبت على جانب الخادم التي تحتوي على التحميل المتزامن يجب أن يكون سهلاً مثل إعادة تعريف required.load (). يقوم نظام البناء بذلك ، يمكن العثور على أسلوب require.load لهذه البيئة في build / jslib / requirePatch.js.

في المستقبل ، قد يتم سحب هذه التعليمة البرمجية في الدليل / الدليل كوحدة اختيارية يمكنك تحميلها في env للحصول على سلوك التحميل الصحيح استنادًا إلى بيئة المضيف.

خيارات الإعداد

عند استخدام يتطلب () في صفحة HTML ذات المستوى الأعلى (أو ملف نصي ذي المستوى الأعلى لا يحدد وحدة نمطية) ، يمكن تمرير كائن تكوين كخيار أول:

<script src="scripts/require.js"></script>
<script>
  require.config({
    baseUrl: "/another/path",
    paths: {
        "some": "some/v1.0"
    },
    waitSeconds: 15
  });
  require( ["some/module", "my/module", "a.js", "b.js"],
    function(someModule,    myModule) {
        //This function will be called when all the dependencies
        //listed above are loaded. Note that this function could
        //be called before the page is loaded.
        //This callback is optional.
    }
  );
</script>

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

أيضا ، يمكنك تعريف كائن التكوين كما require المتغير الشامل قبل require.js ، ويتم تطبيق القيم تلقائيا. يحدد هذا المثال بعض الاعتماديات للتحميل في أقرب وقت يتطلب request.js يحدد ():

<script>
    var require = {
        deps: ["some/module1", "my/module2", "a.js", "b.js"],
        callback: function(module1, module2) {
            //This function will be called when all the dependencies
            //listed above in deps are loaded. Note that this
            //function could be called before the page is loaded.
            //This callback is optional.
        }
    };
</script>
<script src="scripts/require.js"></script>

ملاحظة: من الأفضل استخدام var require = {} ولا تستخدم window.require = {} ، فلن تتصرف بشكل صحيح في IE.

هناك بعض الأنماط لفصل التكوين من تحميل الوحدة الرئيسية .

خيارات التكوين المدعومة:

baseUrl : المسار الجذر لاستخدامه لجميع عمليات البحث في الوحدة النمطية. لذلك في المثال أعلاه ، سيكون للعلامة النصية "my / module" الخاصة بها src = "/ another / path / my / module.js". لا يتم استخدام baseUrl عند تحميل ملفات .js العادية (المشار إليها بواسطة سلسلة تبعية تبدأ بشرطة مائلة أو تحتوي على بروتوكول أو ينتهي بـ .js ) ، يتم استخدام تلك السلاسل كما هو ، لذلك سوف يكون a.js و b.js تحميل من نفس الدليل كصفحة HTML التي تحتوي على المقتطف أعلاه.

إذا لم يتم تعيين baseUrl بشكل صريح في التكوين ، فستكون القيمة الافتراضية هي موقع صفحة HTML التي تحمل require required.js. إذا تم استخدام سمة البيانات الرئيسية ، فسيصبح هذا المسار هو baseUrl.

يمكن أن يكون baseUrl عنوان URL على نطاق مختلف مثل الصفحة التي سيتم تحميل require.js. يعمل تحميل البرنامج النصي RequireJS عبر النطاقات. القيود الوحيدة على محتوى النص تحميلها النص! المكونات الإضافية: يجب أن تكون هذه المسارات على نفس نطاق الصفحة ، على الأقل أثناء التطوير. ستعمل أداة التحسين على تضمين النص! موارد المكون الإضافي حتى بعد استخدام أداة التحسين ، يمكنك استخدام الموارد التي تشير إلى النص! موارد البرنامج المساعد من مجال آخر.

مسارات : تعيينات المسار لأسماء الوحدة النمطية غير موجود مباشرة تحت baseUrl. يفترض أن تكون إعدادات المسار متعلقة بـ baseUrl ، ما لم يبدأ إعداد المسارات بـ "/" أو يحتوي على بروتوكول عنوان URL فيه ("مثل http:"). باستخدام نموذج التكوين أعلاه ، ستكون علامة البرنامج النصي "some / module" src = "/ another / path / some / v1.0 / module.js".

يجب ألا يشتمل المسار المستخدم لاسم وحدة على ملحق ، نظرًا لأن تعيين المسار قد يكون لدليلًا. سيضيف رمز تعيين المسار تلقائيًا ملحق .js عند تعيين اسم الوحدة النمطية إلى مسار. إذا تم استخدام require.toUrl() ، فسيتم إضافة الامتداد المناسب ، إذا كان لشيء مثل قالب نصي.

عند التشغيل في متصفح ، يمكن تحديد مسارات العودة ، للسماح بمحاولة تحميل من موقع CDN ، ولكن الرجوع إلى موقع محلي إذا فشل تحميل موقع CDN.

bundles : المقدمة في RequireJS 2.1.10: تسمح بتكوين معرفات الوحدة النمطية المتعددة في نص برمجي آخر. مثال:

requirejs.config({
    bundles: {
        'primary': ['main', 'util', 'text', 'text!template.html'],
        'secondary': ['text!secondary.html']
    }
});

require(['util', 'text'], function(util, text) {
    //The script for module ID 'primary' was loaded,
    //and that script included the define()'d
    //modules for 'util' and 'text'
});

يوضح هذا التهيئة: "main" و "util" و "text" و "text! template.html" سيتم العثور عليها عن طريق تحميل الوحدة النمطية "الأساسي". يمكن العثور على نص الوحدة النمطية "secondary.html" عن طريق تحميل معرف الوحدة النمطية "ثانوي".

هذا فقط إعداد مكان العثور على وحدة نمطية داخل برنامج نصي يحتوي على عدة تعريفات () 'د في ذلك. لا يتم ربط هذه الوحدات تلقائيًا بمعرف الوحدة النمطية للباقة. يتم استخدام معرّف الوحدة النمطية الحزمة فقط لتحديد موقع مجموعة الوحدات النمطية.

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

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

اعتبارًا من RequireJS 2.2.0 ، يمكن للمحسن إنشاء تكوين الحزم وإدراجه في استدعاء requestjs.config () المستوى الأعلى. راجع الخيار bundlesConfigOutFile config config لمزيد من التفاصيل.

الرقائق : تكوين التبعيات ، والتصدير ، والتهيئة المخصصة للبرامج النصية "globals المتصفح" التقليدية القديمة التي لا تستخدم define () لتوضيح التبعيات وتعيين قيمة وحدة نمطية.

هنا مثال. يتطلب RequireJS 2.1.0+ ، ويفترض أن backbone.js و underscore.js و jquery.js تم تثبيتها في الدليل baseUrl. إذا لم يكن الأمر كذلك ، فقد تحتاج إلى تعيين مسارات التكوين لها:

requirejs.config({
    //Remember: only use shim config for non-AMD scripts,
    //scripts that do not already call define(). The shim
    //config will not work correctly if used on AMD scripts,
    //in particular, the exports and init config will not
    //be triggered, and the deps config will be confusing
    //for those cases.
    shim: {
        'backbone': {
            //These script dependencies should be loaded before loading
            //backbone.js
            deps: ['underscore', 'jquery'],
            //Once loaded, use the global 'Backbone' as the
            //module value.
            exports: 'Backbone'
        },
        'underscore': {
            exports: '_'
        },
        'foo': {
            deps: ['bar'],
            exports: 'Foo',
            init: function (bar) {
                //Using a function allows you to call noConflict for
                //libraries that support it, and do other cleanup.
                //However, plugins for those libraries may still want
                //a global. "this" for the function will be the global
                //object. The dependencies will be passed in as
                //function arguments. If this function returns a value,
                //then that value is used as the module export value
                //instead of the object found via the 'exports' string.
                //Note: jQuery registers as an AMD module via define(),
                //so this will not work for jQuery. See notes section
                //below for an approach for jQuery.
                return this.Foo.noConflict();
            }
        }
    }
});

//Then, later in a separate file, call it 'MyModel.js', a module is
//defined, specifying 'backbone' as a dependency. RequireJS will use
//the shim config to properly load 'backbone' and give a local
//reference to this module. The global Backbone will still exist on
//the page too.
define(['backbone'], function (Backbone) {
  return Backbone.Model.extend({});
});

في RequireJS 2.0. * ، قد تكون الخاصية "exports" في تكوين الرقاقة دالة بدلاً من سلسلة. في هذه الحالة ، كان يعمل بنفس خاصية "init" كما هو موضح أعلاه. يتم استخدام نمط "init" في RequireJS 2.1.0+ بحيث يمكن استخدام قيمة سلسلة exports من أجل enforceDefine ، ثم السماح بالعمل الوظيفي بمجرد أن يتم تحميل المكتبة.

بالنسبة إلى "الوحدات النمطية" التي هي مجرد مكونات jQuery أو Backbone لا تحتاج إلى تصدير أي قيمة وحدة نمطية ، يمكن أن يكون تكوين الرقاقة عبارة عن مصفوفة من التبعيات:

requirejs.config({
    shim: {
        'jquery.colorize': ['jquery'],
        'jquery.scroll': ['jquery'],
        'backbone.layoutmanager': ['backbone']
    }
});

لاحظ مع ذلك إذا كنت ترغب في الحصول على كشف الحمل 404 في IE بحيث يمكنك استخدام مسارات الرجوع أو عمليات التراجع ، فيجب إعطاء قيمة تصدير سلسلة بحيث يمكن لمحمل التحقق من ما إذا كانت البرامج النصية المحملة بالفعل ( لا يتم استخدام إرجاع من init لـ enforceDefine تدقيق):

requirejs.config({
    shim: {
        'jquery.colorize': {
            deps: ['jquery'],
            exports: 'jQuery.fn.colorize'
        },
        'jquery.scroll': {
            deps: ['jquery'],
            exports: 'jQuery.fn.scroll'
        },
        'backbone.layoutmanager': {
            deps: ['backbone']
            exports: 'Backbone.LayoutManager'
        }
    }
});

ملاحظات مهمة عن تهيئة "الرقائق":

  • تهيئة الرقاقة تقوم فقط بإعداد علاقات الكود. لتحميل الوحدات النمطية التي تعد جزءًا من أو استخدام تكوين الرقاقة ، هناك حاجة إلى استدعاء / تعريف اتصال عادي. لا يؤدي تعيين الرقاقة في حد ذاتها إلى تشغيل رمز لتحميل.
  • لا تستخدم سوى وحدات "الرقائق" الأخرى كإعتمادات للنصوص المبثوثة ، أو مكتبات AMD التي ليس لها تبعيات أو تعريف call () بعد أن تقوم أيضًا بإنشاء عالمي (مثل jQuery أو lodash). بخلاف ذلك ، إذا كنت تستخدم وحدة AMD كاعتمادية لوحدة التكوين التبادلي ، بعد الإنشاء ، فقد لا يتم تقييم وحدة AMD هذه إلا بعد تنفيذ الشفرة التي تم تشفيرها في البنية ، وسيحدث خطأ. يتمثل الحل النهائي في ترقية كل الشفرة المتسلسلة للحصول على مكالمات اختيارية () AMD.
  • إذا لم يكن من الممكن ترقية التعليمات البرمجية التي تم تشفيرها لاستخدام مكالمات تعريف () AMD ، اعتبارًا من RequireJS 2.1.11 ، يحتوي المحسن على خيار بناء wrapShim سيحاول تلقائياً التفاف الشفرة التي تم تشكيلها في تعريف () للبناء. يؤدي هذا إلى تغيير نطاق التبعيات المنبهة ، لذلك لا يمكن ضمان العمل دائمًا ، ولكن ، على سبيل المثال ، بالنسبة إلى التبعيات التي يتم تبنيها والتي تعتمد على إصدار AMD من Backbone ، يمكن أن يكون ذلك مفيدًا.
  • لن يتم استدعاء الدالة init لوحدات AMD. على سبيل المثال ، لا يمكنك استخدام دالة init shim للاتصال بـ noQonflict الخاص بـ jQuery. راجع Mapping Modules لاستخدام noConflict لمقاربة بديلة لـ jQuery.
  • لا يتم دعم تكوين Shim عند تشغيل وحدات AMD في العقدة من خلال RequireJS (إنه يعمل من أجل استخدام محسن على الرغم من ذلك). بالاعتماد على الوحدة النمطية التي يتم عرضها ، قد تفشل في العقدة لأن عقدة لا تملك نفس البيئة العالمية مثل المتصفحات. اعتبارا من RequireJS 2.1.7 ، فإنه يحذرك في وحدة التحكم التي لا يتم اعتماد التكوين الرقاقة ، وربما لا تعمل. If you wish to suppress that message, you can pass requirejs.config({ suppress: { nodeShim: true }}); .

Important optimizer notes for "shim" config :

  • You should use the mainConfigFile build option to specify the file where to find the shim config. Otherwise the optimizer will not know of the shim config. The other option is to duplicate the shim config in the build profile.
  • Do not mix CDN loading with shim config in a build. Example scenario: you load jQuery from the CDN but use the shim config to load something like the stock version of Backbone that depends on jQuery. When you do the build, be sure to inline jQuery in the built file and do not load it from the CDN. Otherwise, Backbone will be inlined in the built file and it will execute before the CDN-loaded jQuery will load. This is because the shim config just delays loading of the files until dependencies are loaded, but does not do any auto-wrapping of define. After a build, the dependencies are already inlined, the shim config cannot delay execution of the non-define()'d code until later. define()'d modules do work with CDN loaded code after a build because they properly wrap their source in define factory function that will not execute until dependencies are loaded. So the lesson: shim config is a stop-gap measure for non-modular code, legacy code. define()'d modules are better.
  • For local, multi-file builds, the above CDN advice also applies. For any shimmed script, its dependencies must be loaded before the shimmed script executes. This means either building its dependencies directly in the buid layer that includes the shimmed script, or loading its dependencies with a require([], function (){}) call, then doing a nested require([]) call for the build layer that has the shimmed script.
  • If you are using uglifyjs to minify the code, do not set the uglify option toplevel to true, or if using the command line do not pass -mt . That option mangles the global names that shim uses to find exports.

map : For the given module prefix, instead of loading the module with the given ID, substitute a different module ID.

This sort of capability is really important for larger projects which may have two sets of modules that need to use two different versions of 'foo', but they still need to cooperate with each other.

This is not possible with the context-backed multiversion support . In addition, the paths config is only for setting up root paths for module IDs, not for mapping one module ID to another one.

map example:

requirejs.config({
    map: {
        'some/newmodule': {
            'foo': 'foo1.2'
        },
        'some/oldmodule': {
            'foo': 'foo1.0'
        }
    }
});

If the modules are laid out on disk like this:

  • foo1.0.js
  • foo1.2.js
  • some/
    • newmodule.js
    • oldmodule.js

When 'some/newmodule' does `require('foo')` it will get the foo1.2.js file, and when 'some/oldmodule' does `require('foo')` it will get the foo1.0.js file.

This feature only works well for scripts that are real AMD modules that call define() and register as anonymous modules. Also, only use absolute module IDs for map config. Relative IDs (like '../some/thing' ) do not work.

There is also support for a "*" map value which means "for all modules loaded, use this map config". If there is a more specific map config, that one will take precedence over the star config. مثال:

requirejs.config({
    map: {
        '*': {
            'foo': 'foo1.2'
        },
        'some/oldmodule': {
            'foo': 'foo1.0'
        }
    }
});

Means that for any module except "some/oldmodule", when "foo" is wanted, use "foo1.2" instead. For "some/oldmodule" only, use "foo1.0" when it asks for "foo".

Note: when doing builds with map config, the map config needs to be fed to the optimizer, and the build output must still contain a requirejs config call that sets up the map config. The optimizer does not do ID renaming during the build, because some dependency references in a project could depend on runtime variable state. So the optimizer does not invalidate the need for a map config after the build.

config : There is a common need to pass configuration info to a module. That configuration info is usually known as part of the application, and there needs to be a way to pass that down to a module. In RequireJS, that is done with the config option for requirejs.config(). Modules can then read that info by asking for the special dependency "module" and calling module.config() . مثال:

requirejs.config({
    config: {
        'bar': {
            size: 'large'
        },
        'baz': {
            color: 'blue'
        }
    }
});

//bar.js, which uses simplified CJS wrapping:
//http://requirejs.org/docs/whyamd.html#sugar
define(function (require, exports, module) {
    //Will be the value 'large'
    var size = module.config().size;
});

//baz.js which uses a dependency array,
//it asks for the special module ID, 'module':
//https://github.com/requirejs/requirejs/wiki/Differences-between-the-simplified-CommonJS-wrapper-and-standard-AMD-define#wiki-magic
define(['module'], function (module) {
    //Will be the value 'blue'
    var color = module.config().color;
});

For passing config to a package , target the main module in the package, not the package ID:

requirejs.config({
    //Pass an API key for use in the pixie package's
    //main module.
    config: {
        'pixie/index': {
            apiKey: 'XJKDLNS'
        }
    },
    //Set up config for the "pixie" package, whose main
    //module is the index.js file in the pixie folder.
    packages: [
        {
            name: 'pixie',
            main: 'index'
        }
    ]
});

packages : configures loading modules from CommonJS packages. See the packages topic for more information.

nodeIdCompat : Node treats module ID example.js and example the same. By default these are two different IDs in RequireJS. If you end up using modules installed from npm, then you may need to set this config value to true to avoid resolution issues. This option only applies to treating the ".js" suffix differently, it does not do any other node resolution and evaluation matching such as .json file handling (JSON handling needs a 'json!' loader plugin anyway). Available in 2.1.10 and greater.

waitSeconds : The number of seconds to wait before giving up on loading a script. Setting it to 0 disables the timeout. The default is 7 seconds.

context : A name to give to a loading context. This allows require.js to load multiple versions of modules in a page, as long as each top-level require call specifies a unique context string. To use it correctly, see the Multiversion Support section.

deps : An array of dependencies to load. Useful when require is defined as a config object before require.js is loaded, and you want to specify dependencies to load as soon as require() is defined. Using deps is just like doing a require([]) call, but done as soon as the loader has processed the configuration. It does not block any other require() calls from starting their requests for modules, it is just a way to specify some modules to load asynchronously as part of a config block.

callback : A function to execute after deps have been loaded. Useful when require is defined as a config object before require.js is loaded, and you want to specify a function to require after the configuration's deps array has been loaded.

enforceDefine : If set to true, an error will be thrown if a script loads that does not call define() or have a shim exports string value that can be checked. See Catching load failures in IE for more information.

xhtml : If set to true, document.createElementNS() will be used to create script elements.

urlArgs : Extra query string arguments appended to URLs that RequireJS uses to fetch resources. Most useful to cache bust when the browser or server is not configured correctly. Example cache bust setting for urlArgs:

urlArgs: "bust=" +  (new Date()).getTime()

As of RequireJS 2.2.0, urlArgs can be a function. If a function, it will receive the module ID and the URL as parameters, and it should return a string that will be added to the end of the URL. Return an empty string if no args. Be sure to take care of adding the '?' or '&' depending on the existing state of the URL. مثال:

requirejs.config({
    urlArgs: function(id, url) {
        var args = 'v=1';
        if (url.indexOf('view.html') !== -1) {
            args = 'v=2'
        }

        return (url.indexOf('?') === -1 ? '?' : '&') + args;
    }
});

During development it can be useful to use this, however be sure to remove it before deploying your code.

scriptType : Specify the value for the type="" attribute used for script tags inserted into the document by RequireJS. Default is "text/javascript". To use Firefox's JavaScript 1.8 features, use "text/javascript;version=1.8".

skipDataMain : Introduced in RequireJS 2.1.9: If set to true , skips the data-main attribute scanning done to start module loading. Useful if RequireJS is embedded in a utility library that may interact with other RequireJS library on the page, and the embedded version should not do data-main loading.

Advanced Usage

Loading Modules from Packages

RequireJS supports loading modules that are in a CommonJS Packages directory structure, but some additional configuration needs to be specified for it to work. Specifically, there is support for the following CommonJS Packages features:

  • A package can be associated with a module name/prefix.
  • The package config can specify the following properties for a specific package:
    • name : The name of the package (used for the module name/prefix mapping)
    • location : The location on disk. Locations are relative to the baseUrl configuration value, unless they contain a protocol or start with a front slash (/).
    • main : The name of the module inside the package that should be used when someone does a require for "packageName". The default value is "main", so only specify it if it differs from the default. The value is relative to the package folder.

IMPORTANT NOTES

  • While the packages can have the CommonJS directory layout, the modules themselves should be in a module format that RequireJS can understand. Exception to the rule: if you are using the r.js Node adapter, the modules can be in the traditional CommonJS module format. You can use the CommonJS converter tool if you need to convert traditional CommonJS modules into the async module format that RequireJS uses.
  • Only one version of a package can be used in a project context at a time. You can use RequireJS multiversion support to load two different module contexts, but if you want to use Package A and B in one context and they depend on different versions of Package C, then that will be a problem. This may change in the future.

If you use a similar project layout as specified in the Start Guide , the start of your web project would look something like this (Node/Rhino-based projects are similar, just use the contents of the scripts directory as the top-level project directory):

  • project-directory/
    • project.html
    • scripts/
      • require.js

Here is how the example directory layout looks with two packages, cart and store :

  • project-directory/
    • project.html
    • scripts/
      • cart/
        • main.js
      • store/
        • main.js
        • util.js
      • main.js
      • require.js

project.html will have a script tag like this:

<script data-main="scripts/main" src="scripts/require.js"></script>

This will instruct require.js to load scripts/main.js. main.js uses the "packages" config to set up packages that are relative to require.js, which in this case are the source packages "cart" and "store":

//main.js contents
//Pass a config object to require
require.config({
    "packages": ["cart", "store"]
});

require(["cart", "store", "store/util"],
function (cart,   store,   util) {
    //use the modules as usual.
});

A require of "cart" means that it will be loaded from scripts/cart/main.js , since "main" is the default main module setting supported by RequireJS. A require of "store/util" will be loaded from scripts/store/util.js .

If the "store" package did not follow the "main.js" convention, and looked more like this:

  • project-directory/
    • project.html
    • scripts/
      • cart/
        • main.js
      • store/
        • store.js
        • util.js
      • main.js
      • package.json
      • require.js

Then the RequireJS configuration would look like so:

require.config({
    packages: [
        "cart",
        {
            name: "store",
            main: "store"
        }
    ]
});

To avoid verbosity, it is strongly suggested to always use packages that use "main" convention in their structure.

Multiversion Support

As mentioned in Configuration Options , multiple versions of a module can be loaded in a page by using different "context" configuration options. require.config() returns a require function that will use the context configuration. Here is an example that loads two different versions of the alpha and beta modules (this example is taken from one of the test files):

<script src="../require.js"></script>
<script>
var reqOne = require.config({
  context: "version1",
  baseUrl: "version1"
});

reqOne(["require", "alpha", "beta",],
function(require,   alpha,   beta) {
  log("alpha version is: " + alpha.version); //prints 1
  log("beta version is: " + beta.version); //prints 1

  setTimeout(function() {
    require(["omega"],
      function(omega) {
        log("version1 omega loaded with version: " +
             omega.version); //prints 1
      }
    );
  }, 100);
});

var reqTwo = require.config({
      context: "version2",
      baseUrl: "version2"
    });

reqTwo(["require", "alpha", "beta"],
function(require,   alpha,   beta) {
  log("alpha version is: " + alpha.version); //prints 2
  log("beta version is: " + beta.version); //prints 2

  setTimeout(function() {
    require(["omega"],
      function(omega) {
        log("version2 omega loaded with version: " +
            omega.version); //prints 2
      }
    );
  }, 100);
});
</script>

Note that "require" is specified as a dependency for the module. This allows the require() function that is passed to the function callback to use the right context to load the modules correctly for multiversion support. If "require" is not specified as a dependency, then there will likely be an error.

Loading Code After Page Load

The example above in the Multiversion Support section shows how code can later be loaded by nested require() calls.

Web Worker Support

As of release 0.12, RequireJS can be run inside a Web Worker. Just use importScripts() inside a web worker to load require.js (or the JS file that contains the require() definition), then call require.

You will likely need to set the baseUrl configuration option to make sure require() can find the scripts to load.

You can see an example of its use by looking at one of the files used in the unit test .

Rhino Support

RequireJS can be used in Rhino via the r.js adapter . See the r.js README for more information.

Nashorn Support

As of RequireJS 2.1.16, RequireJS can be used in Nashorn , Java 8+'s JavaScript engine, via the r.js adapter . See the r.js README for more information.

Handling Errors

The general class of errors are 404s for scripts (not found), network timeouts or errors in the scripts that are loaded. RequireJS has a few tools to deal with them: require-specific errbacks, a "paths" array config, and a global requirejs.onError.

The error object passed to errbacks and the global requirejs.onError function will usually contain two custom properties:

  • requireType : A string value with a general classification, like "timeout", "nodefine", "scripterror".
  • requireModules : an array of module names/URLs that timed out.

If you get an error with a requireModules, it probably means other modules that depend on the modules in that requireModules array are not defined.

Catching load failures in IE

Internet Explorer has a set of problems that make it difficult to detect load failures for errbacks/paths fallbacks:

  • script.onerror does not work in IE 6-8. There is no way to know if loading a script generates a 404, worse, it triggers the onreadystatechange with a complete state even in a 404 case.
  • script.onerror does work in IE 9+, but it has a bug where it does not fire script.onload event handlers right after execution of script, so it cannot support the standard method of allowing anonymous AMD modules. So script.onreadystatechange is still used. However, onreadystatechange fires with a complete state before the script.onerror function fires.

So it is very difficult with IE to allow both anonymous AMD modules, which are a core benefit of AMD modules, and reliable detect errors.

However, if you are in a project that you know uses define() to declare all of its modules, or it uses the shim config to specify string exports for anything that does not use define(), then if you set the enforceDefine config value to true, the loader can confirm if a script load by checking for the define() call or the existence of the shim's exports global value.

So if you want to support Internet Explorer, catch load errors, and have modular code either through direct define() calls or shim config, always set enforceDefine to be true. See the next section for an example.

NOTE : If you do set enforceDefine: true, and you use data-main="" to load your main JS module, then that main JS module must call define() instead of require() to load the code it needs. The main JS module can still call require/requirejs to set config values, but for loading modules it should use define().

If you then also use almond to build your code without require.js, be sure to use the insertRequire build setting to insert a require call for the main module -- that serves the same purpose of the initial require() call that data-main does.

require([]) errbacks

Errbacks, when used with requirejs.undef() , will allow you to detect if a module fails to load, undefine that module, reset the config to a another location, then try again.

A common use case for this is to use a CDN-hosted version of a library, but if that fails, switch to loading the file locally:

requirejs.config({
    enforceDefine: true,
    paths: {
        jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min'
    }
});

//Later
require(['jquery'], function ($) {
    //Do something with $ here
}, function (err) {
    //The errback, error callback
    //The error has a list of modules that failed
    var failedId = err.requireModules && err.requireModules[0];
    if (failedId === 'jquery') {
        //undef is function only on the global requirejs object.
        //Use it to clear internal knowledge of jQuery. Any modules
        //that were dependent on jQuery and in the middle of loading
        //will not be loaded yet, they will wait until a valid jQuery
        //does load.
        requirejs.undef(failedId);

        //Set the path to jQuery to local path
        requirejs.config({
            paths: {
                jquery: 'local/jquery'
            }
        });

        //Try again. Note that the above require callback
        //with the "Do something with $ here" comment will
        //be called if this new attempt to load jQuery succeeds.
        require(['jquery'], function () {});
    } else {
        //Some other error. Maybe show message to the user.
    }
});

With `requirejs.undef()`, if you later set up a different config and try to load the same module, the loader will still remember which modules needed that dependency and finish loading them when the newly configured module loads.

Note : errbacks only work with callback-style require calls, not define() calls. define() is only for declaring modules.

paths config fallbacks

The above pattern for detecting a load failure, undef()ing a module, modifying paths and reloading is a common enough request that there is also a shorthand for it. The paths config allows array values:

requirejs.config({
    //To get timely, correct error triggers in IE, force a define/shim exports check.
    enforceDefine: true,
    paths: {
        jquery: [
            'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min',
            //If the CDN location fails, load from this location
            'lib/jquery'
        ]
    }
});

//Later
require(['jquery'], function ($) {
});

This above code will try the CDN location, but if that fails, fall back to the local lib/jquery.js location.

Note : paths fallbacks only work for exact module ID matches. This is different from normal paths config which can apply to any part of a module ID prefix segment. Fallbacks are targeted more for unusual error recovery, not a generic path search path solution, since those are inefficient in the browser.

Global requirejs.onError function

To detect errors that are not caught by local errbacks, you can override requirejs.onError():

requirejs.onError = function (err) {
    console.log(err.requireType);
    if (err.requireType === 'timeout') {
        console.log('modules: ' + err.requireModules);
    }

    throw err;
};

Loader Plugins

RequireJS supports loader plugins . This is a way to support dependencies that are not plain JS files, but are still important for a script to have loaded before it can do its work. The RequireJS wiki has a list of plugins . This section talks about some specific plugins that are maintained alongside RequireJS:

Specify a Text File Dependency

It is nice to build HTML using regular HTML tags, instead of building up DOM structures in script. However, there is no good way to embed HTML in a JavaScript file. The best that can be done is using a string of HTML, but that can be hard to manage, particularly for multi-line HTML.

RequireJS has a plugin, text.js, that can help with this issue. It will automatically be loaded if the text! prefix is used for a dependency. See the text.js README for more information.

Page Load Event Support/DOM Ready

It is possible when using RequireJS to load scripts quickly enough that they complete before the DOM is ready. Any work that tries to interact with the DOM should wait for the DOM to be ready. For modern browsers, this is done by waiting for the DOMContentLoaded event.

However, not all browsers in use support DOMContentLoaded. The domReady module implements a cross-browser method to determine when the DOM is ready. Download the module and use it in your project like so:

require(['domReady'], function (domReady) {
  domReady(function () {
    //This function is called once the DOM is ready.
    //It will be safe to query the DOM and manipulate
    //DOM nodes in this function.
  });
});

نظرًا لأن DOM جاهز للاستخدام هو حاجة شائعة للتطبيق ، فمن الأفضل تجنب الوظائف المتداخلة في API أعلاه. تقوم أيضًا وحدة domReady بتنفيذ واجهة برمجة تطبيقات Loader Plugin ، لذلك يمكنك استخدام بنية المكون الإضافي للمحلل (لاحظ الـ ! in the domReady dependency) لإجبار وظيفة الاستدعاء () callback على الانتظار حتى يصبح DOM جاهزًا قبل التنفيذ.

domReady
سيعرض المستند الحالي عند استخدامه كمكوّن إضافي للمحلل:
require(['domReady!'], function (doc) {
    //This function is called once the DOM is ready,
    //notice the value for 'domReady!' is the current
    //document.
});

Note: If the document takes a while to load (maybe it is a very large document, or has HTML script tags loading large JS files that block DOM completion until they are done), using domReady as a loader plugin may result in a RequireJS "timeout" error. If this is a problem either increase the waitSeconds configuration, or just use domReady as a module and call domReady() inside the require() callback.

Define an I18N Bundle

Once your web app gets to a certain size and popularity, localizing the strings in the interface and providing other locale-specific information becomes more useful. However, it can be cumbersome to work out a scheme that scales well for supporting multiple locales.

RequireJS allows you to set up a basic module that has localized information without forcing you to provide all locale-specific information up front. It can be added over time, and only strings/values that change between locales can be defined in the locale-specific file.

i18n bundle support is provided by the i18n.js plugin. It is automatically loaded when a module or dependency specifies the i18n! prefix (more info below). Download the plugin and put it in the same directory as your app's main JS file.

To define a bundle, put it in a directory called "nls" -- the i18n! plugin assumes a module name with "nls" in it indicates an i18n bundle. The "nls" marker in the name tells the i18n plugin where to expect the locale directories (they should be immediate children of the nls directory). If you wanted to provide a bundle of color names in your "my" set of modules, create the directory structure like so:

  • my/nls/colors.js

The contents of that file should look like so:

//my/nls/colors.js contents:
define({
    "root": {
        "red": "red",
        "blue": "blue",
        "green": "green"
    }
});

An object literal with a property of "root" defines this module. That is all you have to do to set the stage for later localization work.

You can then use the above module in another module, say, in a my/lamps.js file:

//Contents of my/lamps.js
define(["i18n!my/nls/colors"], function(colors) {
    return {
        testMessage: "The name for red in this locale is: " + colors.red
    }
});

The my/lamps module has one property called "testMessage" that uses colors.red to show the localized value for the color red.

Later, when you want to add a specific translation to a file, say for the fr-fr locale, change my/nls/colors to look like so:

//Contents of my/nls/colors.js
define({
    "root": {
        "red": "red",
        "blue": "blue",
        "green": "green"
    },
    "fr-fr": true
});

Then define a file at my/nls/fr-fr/colors.js that has the following contents:

//Contents of my/nls/fr-fr/colors.js
define({
    "red": "rouge",
    "blue": "bleu",
    "green": "vert"
});

RequireJS will use the browser's navigator.languages, navigator.language or navigator.userLanguage property to determine what locale values to use for my/nls/colors, so your app does not have to change. If you prefer to set the locale, you can use the config to pass the locale to the plugin:

requirejs.config({
    config: {
        //Set the config for the i18n
        //module ID
        i18n: {
            locale: 'fr-fr'
        }
    }
});

Note that RequireJS will always use a lowercase version of the locale, to avoid case issues, so all of the directories and files on disk for i18n bundles should use lowercase locales.

RequireJS is also smart enough to pick the right locale bundle, the one that most closely matches the ones provided by my/nls/colors. For instance, if the locale is "en-us", then the "root" bundle will be used. If the locale is "fr-fr-paris" then the "fr-fr" bundle will be used.

RequireJS also combines bundles together, so for instance, if the french bundle was defined like so (omitting a value for red):

//Contents of my/nls/fr-fr/colors.js
define({
    "blue": "bleu",
    "green": "vert"
});

Then the value for red in "root" will be used. This works for all locale pieces. If all the bundles listed below were defined, then RequireJS will use the values in the following priority order (the one at the top takes the most precedence):

  • my/nls/fr-fr-paris/colors.js
  • my/nls/fr-fr/colors.js
  • my/nls/fr/colors.js
  • my/nls/colors.js

If you prefer to not include the root bundle in the top level module, you can define it like a normal locale bundle. In that case, the top level module would look like:

//my/nls/colors.js contents:
define({
    "root": true,
    "fr-fr": true,
    "fr-fr-paris": true
});

and the root bundle would look like:

//Contents of my/nls/root/colors.js
define({
    "red": "red",
    "blue": "blue",
    "green": "green"
});

原文