يمكنك نشر محتوى JavaScript حديث وشحنه وتثبيته للحصول على تطبيقات أسرع.

يمكنك تحسين الأداء من خلال تفعيل اعتماديات ومخرجات JavaScript الحديثة.

تستطيع أكثر من 90% من المتصفحات تشغيل JavaScript حديث، ولكن يبقى انتشار JavaScript القديمة مصدرًا كبيرًا للمشاكل في الأداء على الويب اليوم.

JavaScript حديث

لا توصف لغة JavaScript الحديثة بأنها تعليمة برمجية مكتوبة بلغة ECMAScript محددة ولكن بدلًا من ذلك في بناء الجملة الذي تدعمه جميع المتصفحات. مكوّنات الويب الحديثة، مثل Chrome وEdge وFirefox وSafari لأكثر من 90% من سوق المتصفّحات المتصفحات المختلفة التي تعتمد على محركات العرض الأساسية نفسها يكوّنون 5٪ إضافية. وهذا يعني أنّ نسبة% 95 من عدد زيارات الويب العالمية مصدرها المتصفّحات التي تتوافق مع ميزات لغة JavaScript الأكثر استخدامًا من آخر 10 تطبيقات سنوات، بما في ذلك:

  • الفئات (ES2015)
  • الدوال السهمية (ES2015)
  • مولّدات كهرباء (ES2015)
  • تحديد نطاق الحظر (ES2015)
  • التدمير (ES2015)
  • معلمات الراحة والتوزيع (ES2015)
  • اختصار الكائن (ES2015)
  • Async/await (ES2017)

تحتوي الميزات في الإصدارات الأحدث من مواصفات اللغة بشكل عام على عدد أقل دعم متسق عبر المتصفحات الحديثة. على سبيل المثال، يحتوي العديد من ES2020 وES2021 الميزات الجديدة متاحة في 70% فقط من سوق المتصفحات، ولا تزال غالبية المتصفحات، لكنه ليس كافيًا ليكون الاعتماد على هذه الميزات بشكلٍ مباشر آمن. هذا النمط تعني أنه على الرغم من أن كلمة "حديث" تُعد JavaScript هدفًا متحركًا، لذلك يحتوي ES2017 على أوسع نطاق من التوافق مع المتصفحات مع تضمين معظم ميزات البنية الحديثة الشائعة الاستخدام. بعبارة أخرى، ES2017 هي الأقرب إلى البنية الحديثة.

JavaScript قديم

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

  • عادةً ما يكون إصدار JavaScript القديم أكبر وأبطأ بنسبة 20% تقريبًا من أي رمز حديث مكافئ. أوجه القصور في الأدوات والتهيئة الخاطئة غالبًا وتوسيع هذه الفجوة بشكل أكبر.

  • تشكل المكتبات المثبّتة نسبة 90% من عمليات الإنتاج المعتادة. رمز JavaScript. يجب أن يتوفر في رمز المكتبة رمز JavaScript قديم النفقات العامة التي يمكن تجنّبها بسبب استخدام عناصر polyfill المتكررة من خلال نشر الرموز الحديثة

لغة JavaScript حديثة في npm

وقد وحّدت Node.js مؤخرًا الحقل "exports" لتحديد نقاط الدخول للحزمة:

{
  "exports": "./index.js"
}

تشير الوحدات المُشار إليها في الحقل "exports" إلى إصدار عقدة على الأقل. 12.8، والذي يتوافق مع ES2019 وهذا يعني أن أي وحدة تتم الإشارة إليها باستخدام يمكن كتابة الحقل "exports" باستخدام JavaScript حديث. على مستهلكي الحِزم لنفترض أنّ الوحدات التي تحتوي على حقل "exports" تحتوي على رمز حديث والتحويل إذا اللازمة.

تصميم عصري فقط

إذا كنت تريد نشر حزمة برموز برمجية حديثة واتركها كما هي المستهلك في التعامل مع عملية التحويل عند استخدامها عند استخدامها كتبعية؛ استخدم فقط الحقل ""exports"".

{
  "name": "foo",
  "exports": "./modern.js"
}

تصميم عصري بتصميم احتياطي قديم

استخدِم الحقل "exports" مع "main" لنشر حزمتك. باستخدام رموز برمجية حديثة ولكنها تتضمن أيضًا احتياطي ES5 + CommonJS للإصدار القديم المتصفحات.

{
  "name": "foo",
  "exports": "./modern.js",
  "main": "./legacy.cjs"
}

أدوات عصرية تشمل إجراءات احتياطية قديمة وتحسينات خاصة بحزم إدارة المشروعات (ESM)

بالإضافة إلى تحديد نقطة إدخال CommonJS الاحتياطية، يمكن للحقل "module" يُستخدم للإشارة إلى حزمة احتياطية قديمة مشابهة، ولكن واحدة تستخدم بنية وحدة JavaScript (import وexport)

{
  "name": "foo",
  "exports": "./modern.js",
  "main": "./legacy.cjs",
  "module": "./module.js"
}

تعتمد العديد من برامج تجميع البيانات، مثل webpack وRollup، على هذا الحقل للاستفادة من ميزات الوحدة وإتاحة اهتزاز الشجرة. لا تزال هذه حزمة قديمة لا تحتوي على أي رموز برمجية حديثة بناءً على البنية import/export، يمكنك استخدام هذه الطريقة لإرسال رمز برمجي حديث عنصر احتياطي قديم لا يزال محسَّنًا للتجميع.

استخدام JavaScript حديث في التطبيقات

تشكِّل التبعيات التابعة لجهات خارجية الغالبية العظمى من عمليات الإنتاج النموذجية رمز JavaScript في تطبيقات الويب. وفي حين أن تبعيات npm كانت لها تاريخ تم نشرها كبنية ES5 قديمة، فلم يعد ذلك افتراضًا آمنًا تحديثات التبعية ومخاطر أخرى تؤدي إلى إيقاف دعم المتصفح في تطبيقك.

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

حزمة ويب

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

module.exports = {
  target: ['web', 'es2017'],
};

ومن الممكن أيضًا تهيئة حزمة ويب لإنشاء حزم محسنة حذف دوال التضمين غير الضرورية عند استهداف وحدات ES حديثة محددة. يؤدي هذا أيضًا إلى تهيئة webpack لتحميل حزم تقسيم التعليمات البرمجية باستخدام <script type="module">

module.exports = {
  target: ['web', 'es2017'],
  output: {
    module: true,
  },
  experiments: {
    outputModule: true,
  },
};

يتوفر عدد من المكونات الإضافية لحزمة الويب والتي تتيح تجميع وشحن JavaScript حديث مع الاستمرار في دعم المتصفحات القديمة، مثل المكوّن الإضافي "أدوات تحسين الأداء" وBabelEsmplin.

المكوّن الإضافي "أدوات تحسين الأداء"

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

وبما أن المكوّن الإضافي "أدوات تحسين الأداء" يعمل على حِزم بدلاً من وحدات فردية، فإنّه يعالج تعليمة برمجية لتطبيقك وتبعياتك بالتساوي. هذا يجعل من من الأمان استخدام تبعيات JavaScript الحديثة من npm، لأن الرمز البرمجي الخاص بالمجموعة ستكون مجمعة وترجمتها إلى بناء الجملة الصحيح. يمكن أيضًا أن يكون أسرع من والحلول التقليدية التي تتضمن خطوتين للتجميع، مع الاستمرار في إنشاء حزم منفصلة للمتصفحات الحديثة والقديمة. مجموعتا الحزم هما مصممة لتحميلها باستخدام unit/nomodule style:

// webpack.config.js
const OptimizePlugin = require('optimize-plugin');

module.exports = {
  // ...
  plugins: [new OptimizePlugin()],
};

يمكن أن يكون Optimize Plugin أسرع وأكثر كفاءة من حزمة الويب المخصّصة. والذي يجمع عادةً بين الرموز الحديثة والقديمة بشكل منفصل. أُنشأها جون هنتر، الذي كان متخصصًا أيضًا معالجة Babel نيابةً عنك، وتقليل باستخدام Terser مع إعدادات مثالية منفصلة المخرجات الحديثة والقديمة. وأخيرًا، لا بد من ظهور رموز polyfills التي تم إنشاؤها بواسطة يتم استخراج الحِزم القديمة في نص برمجي مخصّص لكي لا يتم مكررة أو محملة بشكل غير ضروري في المتصفحات الجديدة.

المقارنة: ترجمة وحدات المصدر مرتين مقابل ترجمة الحزم التي تم إنشاؤها.

BabelEsmPlugin

BabelEsmPlugin هو حزمة ويب. المكون الإضافي الذي يعمل مع @babel/preset-env لإنشاء إصدارات حديثة من الحِزم الحالية لشحن رموز أقل يتم نقلها إلى المتصفحات الحديثة. وهو أكثر الحلول الجاهزة شيوعًا unit/noModule، ويستخدمهما Next.js واجهة سطر الأوامر (Preact CLI):

// webpack.config.js
const BabelEsmPlugin = require('babel-esm-plugin');

module.exports = {
  //...
  module: {
    rules: [
      // your existing babel-loader configuration:
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
  plugins: [new BabelEsmPlugin()],
};

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

ضبط أداة تحميل babel على نقل num_modules

في حال استخدام babel-loader بدون أحد المكوِّنَين الإضافيَين السابقَين، هناك خطوة مهمة مطلوبة لاستهلاك npm لرموز JavaScript الحديثة الوحدات. يتيح تحديد ضبطَين منفصلَين لـ babel-loader. لتجميع الميزات اللغوية الحديثة المتوفّرة في node_modules تلقائيًا من أجل ES2017، مع مواصلة تحويل رمز الطرف الأول الخاص بك باستخدام Babel والمكونات الإضافية والإعدادات المسبقة المحددة في تهيئة مشروعك. لن يؤدي هذا الإجراء إلى حزم حديثة وقديمة لإعداد وحدة أو أي وحدة إتاحة إمكانية تثبيت واستخدام حزم npm التي تحتوي على JavaScript حديث بدون تعطيل المتصفحات القديمة.

webpack-plugin-modern-npm يستخدم هذا الأسلوب لتجميع اعتماديات npm التي تحتوي على حقل "exports" في package.json، لأنها قد تحتوي على بنية حديثة:

// webpack.config.js
const ModernNpmPlugin = require('webpack-plugin-modern-npm');

module.exports = {
  plugins: [
    // auto-transpile modern stuff found in node_modules
    new ModernNpmPlugin(),
  ],
};

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

// webpack.config.js
module.exports = {
  module: {
    rules: [
      // Transpile for your own first-party code:
      {
        test: /\.js$/i,
        loader: 'babel-loader',
        exclude: /node_modules/,
      },
      // Transpile modern dependencies:
      {
        test: /\.js$/i,
        include(file) {
          let dir = file.match(/^.*[/\\]node_modules[/\\](@.*?[/\\])?.*?[/\\]/);
          try {
            return dir && !!require(dir[0] + 'package.json').exports;
          } catch (e) {}
        },
        use: {
          loader: 'babel-loader',
          options: {
            babelrc: false,
            configFile: false,
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
};

عند استخدام هذه الطريقة، سينبغي لك التأكد من دعم بناء الجملة الحديث صغيرك. كل من Terser وuglify-es يمكنكم تحديد {ecma: 2017} للاحتفاظ بهم، وفي بعض الحالات، إنشاء بنية ES2017 أثناء الضغط والتنسيق.

البيانات المجمّعة

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

@rollup/plugin-babel

إذا كنت تستخدم ميزة "دمج البيانات"، طريقة getBabelOutputPlugin() (توفّرها منصة البيانات المجمّعة المكون الإضافي الرسمي لـ Babel) تحوِّل الرمز في الحزم التي تم إنشاؤها بدلاً من الوحدات المصدر الفردية. توفّر خدمة البيانات المجمّعة إمكانية إنشاء مجموعات متعدّدة من الحِزم كجزء من إصدار واحد، ولكل منها مكونات إضافية خاصة به. يمكنك استخدام هذا لإنتاج حِزم مختلفة للّعبة القديمة والحديثة من خلال إرسال كل منها إعداد المكون الإضافي للمخرجات في Babel:

// rollup.config.js
import {getBabelOutputPlugin} from '@rollup/plugin-babel';

export default {
  input: 'src/index.js',
  output: [
    // modern bundles:
    {
      format: 'es',
      plugins: [
        getBabelOutputPlugin({
          presets: [
            [
              '@babel/preset-env',
              {
                targets: {esmodules: true},
                bugfixes: true,
                loose: true,
              },
            ],
          ],
        }),
      ],
    },
    // legacy (ES5) bundles:
    {
      format: 'amd',
      entryFileNames: '[name].legacy.js',
      chunkFileNames: '[name]-[hash].legacy.js',
      plugins: [
        getBabelOutputPlugin({
          presets: ['@babel/preset-env'],
        }),
      ],
    },
  ],
};

أدوات تصميم إضافية

يكون دمج حزمة الويب وحزم الويب سهلَين بدرجة كبيرة، ما يعني بشكل عام أنّ كل مشروع تعديل الإعدادات لتفعيل بنية JavaScript الحديثة في التبعيات. هناك أيضًا أدوات تصميم ذات مستوى أعلى تفضِّل استخدام الاصطلاحات والخيارات التلقائية بدلاً من ذلك. مثل Parcel وSnowpack وVite وWMR. معظم هذه الأدوات لنفترض أن تبعيات npm قد تحتوي على بناء جملة حديث، وسيتم تحويلها إلى مستويات بناء الجملة المناسبة عند الإنشاء للإنتاج.

بالإضافة إلى المكونات الإضافية المخصصة لـ webpack وRollup، تتوفر ميزات JavaScript الحديثة يمكن إضافة حزم بحزم احتياطية قديمة إلى أي مشروع باستخدام devolution. التطور هو أداة مستقلة تحول المخرجات من نظام تصميم لإنتاج بيانات متغيرات جافا سكريبت، ما يسمح للتجميع والتحويل بافتراض تحديث الناتج.