مجموعة التحديثات: يمكنك بالفعل إنشاء تطبيقات

Rollup هو تطبيق جافا سكريبت جديد وباني مكتبة. عرفه الكثير من الناس لفترة طويلة باعتباره منشئًا واعدًا مناسبًا تمامًا لبناء المكتبات ، ولكنه مناسب جدًا لبناء التطبيقات. ومع ذلك ، مع مرور الوقت ، يتطور المنتج بنشاط.

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

لفهم الفوائد ، دعنا نتعرف على الميزات الرئيسية والمقارنة مع Webpack (الموقف هو نفسه بالنسبة لـ Browserify).

التكوين بسيط


على الفور ما يلفت انتباهك هو تكوين بسيط جدا ومفهوم:

export default [{ input: 'src/index.ts', output: [{ file: 'dist/index.min.js', format: 'iife' }], plugins: [ // todo:     ], }]; 

أدخل مجموعة التحديثات -c في cosnol وتبدأ الحزمة الخاصة بك في التجمع. للتصدير ، يمكنك إعطاء مجموعة من الحزم للتجميع ، على سبيل المثال ، إذا قمت بتجميع polyphiles بشكل منفصل ، والعديد من البرامج ، والعمال وما إلى ذلك. في المدخلات ، يمكنك إرسال مجموعة من الملفات ، ثم سيتم جمع قطع. في الإخراج ، يمكنك تغذية مجموعة من ملفات الإخراج وتجميعها في أنظمة معيارية مختلفة: iife ، commonjs ، umd.

دعم Iife


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

 console.log("Hello, world!"); 

قيادتها من خلال Rollup إلى تنسيق iife وشاهد النتيجة:

 (function () { 'use strict'; console.log("Hello, world!"); }()); 

الإخراج هو رمز مضغوط للغاية ، فقط 69 بايت. إذا كنت لا تزال لا تفهم الميزة ، فسوف تقوم Webpack / Browserify بتجميع التعليمات البرمجية التالية:

Webpack بناء النتيجة
 /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { console.log("Hello, world!"); /***/ }) /******/ ]); 


كما ترون ، اتضح أن الأمر قد زاد قليلاً بسبب حقيقة أنه لا يمكن بناء Webpack / Browserify إلا في CommonJS. الميزة الكبيرة لـ IIFE هي ضغطها وغياب التعارضات بين الإصدارات المختلفة من CommonJS. لكن هناك عيبًا واحدًا ، لا يمكنك جمع القطع ، فبالنسبة لهم تحتاج إلى التبديل إلى CommonJS.

تجميع في ES2015


تم استلام مجموعة التحديثات "التجميع من الجيل التالي" في عام 2016 من أجل القدرة على التجميع في ES2015. وحتى نهاية عام 2018 ، كان المجمع الوحيد الذي عرف كيف يفعل ذلك.
على سبيل المثال ، إذا كنت تأخذ الرمز:

 export class TestA { getData(){return "A"} } console.log("Hello, world!", new TestB().getData()); 

والقيادة من خلال Rollup ، ثم في الإخراج نحصل على نفس الشيء. ونعم! في بداية عام 2019 ، يمكن بالفعل 87 ٪ من المتصفحات تنفيذها أصلا.

ثم في عام 2016 ، بدا الأمر وكأنه تقدم كبير ، لأنه كان هناك عدد كبير من التطبيقات التي لم تكن بحاجة إلى دعم للمتصفحات القديمة: المشرفين ، الأكشاك ، وليس تطبيقات الويب ، ولم تكن هناك أدوات بناء لهم. والآن مع Rollup يمكننا جمع عدة حزم في مسار واحد ، في es3 ، es5 ، es2015 ، exnext واعتمادًا على المتصفح قم بتنزيل الحزمة الضرورية.

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

شجرة تهتز


هذا هو رقاقة Rollup ، اخترع ذلك! تحاول Webpack تنفيذه لسنوات عديدة على التوالي ، لكن مع الإصدار 4 فقط بدأ شيء ما في العمل. Browserify يفعل سيئة للغاية.
أي نوع من الحيوانات هذا؟ لنأخذ الملفين التاليين كمثال:

 // module.ts export class TestA { getData(){return "A"} } export class TestB { getData(){return "B"} } // index.ts import { TestB } from './module'; const test = new TestB(); console.log("Hello, world!", test.getData()); 

ركض عبر Rollup واحصل على:

 (function () { 'use strict'; class TestB { getData() { return "B"; } } const test = new TestB(); console.log("Hello, world!", test.getData()); }()); 

نتيجة ل TreeShaking ، تم تجاهل الكود الميت حتى في مرحلة حل التبعيات. بفضل ما تتحول إليه مجموعات Rollup أكثر إحكاما. الآن دعونا نرى ما يولد Webpack:

Webpack بناء النتيجة
 /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); // CONCATENATED MODULE: ./src/module.ts class TestA { getData() { return "A"; } } class TestB { getData() { return "B"; } } // CONCATENATED MODULE: ./src/index.ts const test = new TestB(); console.log("Hello, world!", test.getData()); /***/ }) /******/ ]); 


وهنا يمكننا استخلاص استنتاجين. لا يزال تعلم Webpack الأول في نهاية عام 2018 لفهم وبناء ES2015. الثاني ، تماما كل رمز يقع في التجمع ، ولكن تمت إزالة الكود الميت بالفعل باستخدام مصغر Terser (شوكة وخليفة ل UglifyES). نتيجة لهذا النهج ، فإن حزم أكثر سمكا من Rollup ، على هابر كتبت بالفعل الكثير عنها ، لن نتوقف عن ذلك.

الإضافات


يمكن تجميع ES2015 + المجردة فقط من مربع مجموعة التحديثات. لتعليمه وظائف إضافية ، مثل توصيل commonjs ، والوحدات النمطية للطباعة ، وتحميل html و scss ، وما إلى ذلك ، تحتاج إلى توصيل المكونات الإضافية.

يتم ذلك ببساطة شديدة:
 import nodeResolve from 'rollup-plugin-node-resolve'; import commonJs from 'rollup-plugin-commonjs'; import typeScript from 'rollup-plugin-typescript2'; import postcss from 'rollup-plugin-postcss'; import html from 'rollup-plugin-html'; import visualizer from 'rollup-plugin-visualizer'; import {sizeSnapshot} from "rollup-plugin-size-snapshot"; import {terser} from 'rollup-plugin-terser'; export default [{ input: 'src/index.ts', output: [{ file: 'dist/index.r.min.js', format: 'iife' }], plugins: [ nodeResolve(), //   node commonJs(), //   commonjs postcss(), //   postcc,    scss  less html(), //  html  typeScript({tsconfig: "tsconfig.json"}), //  typescript sizeSnapshot(), //      terser(), //    ES2015+,    UglifyES visualizer() //   ] }]; 

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

ملخص


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

 import nodeResolve from 'rollup-plugin-node-resolve'; import commonJs from 'rollup-plugin-commonjs'; import typeScript from 'rollup-plugin-typescript2'; import postcss from 'rollup-plugin-postcss'; import html from 'rollup-plugin-html'; import visualizer from 'rollup-plugin-visualizer'; import { sizeSnapshot } from "rollup-plugin-size-snapshot"; import { terser } from 'rollup-plugin-terser'; const getPlugins = (options) => [ nodeResolve(), commonJs(), postcss(), html(), typeScript({ tsconfig: "tsconfig.json", tsconfigOverride: { compilerOptions: { "target": options.target } } }), sizeSnapshot(), terser(), visualizer() ]; export default [{ input: 'src/polyfills.ts', output: [{ file: 'dist/polyfills.min.js', format: 'iife' }], plugins: getPlugins({ target: "es5" }) },{ input: 'src/index.ts', output: [{ file: 'dist/index.next.min.js', format: 'iife' }], plugins: getPlugins({ target: "esnext" }) },{ input: 'src/index.ts', output: [{ file: 'dist/index.es5.min.js', format: 'iife' }], plugins: getPlugins({ target: "es5" }) },{ input: 'src/index.ts', output: [{ file: 'dist/index.es3.min.js', format: 'iife' }], plugins: getPlugins({ target: "es3" }) },{ input: 'src/serviceworker.ts', output: [{ file: 'dist/serviceworker.min.js', format: 'iife' }], plugins: getPlugins({ target: "es5" }) },{ input: 'src/webworker.ts', output: [{ file: 'dist/webworker.min.js', format: 'iife' }], plugins: getPlugins({ target: "es5" }) }]; 


جميع الحزم السهلة وتطبيقات الويب السريعة!

Source: https://habr.com/ru/post/ar440946/


All Articles