Rollup: Anda sudah dapat membangun aplikasi

Rollup adalah aplikasi javascript generasi baru dan pembuat perpustakaan. Banyak yang sudah mengenalnya sejak lama sebagai pembangun yang menjanjikan yang sangat cocok untuk membangun perpustakaan, tetapi tidak cocok untuk membangun aplikasi. Namun, seiring berjalannya waktu, produk ini aktif berkembang.

Saya pertama kali mencobanya di awal 2017. Saya langsung menyukainya karena mendukung kompilasi di ES2015, treeshaking, kurangnya modul dalam perakitan, dan tentu saja konfigurasi sederhana. Tapi kemudian itu adalah produk mentah, dengan sejumlah kecil plugin dan fungsi yang sangat terbatas, dan saya memutuskan untuk meninggalkannya untuk nanti dan terus membangun melalui browserify. Upaya kedua adalah pada tahun 2018, ketika sudah secara signifikan mengungguli komunitas, plugin dan fungsionalitas, tetapi masih kurang kualitas dalam beberapa fungsi, termasuk pengamat. Dan akhirnya, pada awal 2019, kita dapat dengan aman mengatakan - dengan bantuan Rollup Anda dapat dengan mudah dan mudah membangun aplikasi modern.

Untuk memahami manfaatnya, mari kita lihat fitur-fitur utama dan bandingkan dengan Webpack (situasinya sama untuk Browserify).

Konfigurasi sederhana


Segera apa yang menarik perhatian Anda adalah konfigurasi yang sangat sederhana dan mudah dipahami:

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

Masukkan rollup -c di cosnol dan bundel Anda mulai berkumpul. Untuk ekspor, Anda dapat memberikan array bundel untuk perakitan, misalnya, jika Anda mengumpulkan polifil secara terpisah, beberapa program, pekerja dan sebagainya. Sebagai input, Anda dapat mengirimkan berbagai file, kemudian potongan akan dikumpulkan. Dalam output, Anda dapat memberi makan array file output dan mengumpulkannya ke dalam sistem modular yang berbeda: iife, commonjs, umd.

Dukungan Iife


Dukungan untuk perakitan menjadi fungsi itu sendiri yang disebut tanpa modul Untuk pemahaman, mari kita ambil program yang paling terkenal:

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

mengendarainya melalui Rollup ke format iife dan lihat hasilnya:

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

Outputnya adalah kode yang sangat kompak, hanya 69 byte. Jika Anda masih tidak mengerti keuntungannya, Webpack / Browserify akan mengkompilasi kode berikut:

Hasil pembuatan 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!"); /***/ }) /******/ ]); 


Seperti yang Anda lihat, ternyata sedikit lebih karena kenyataan bahwa Webpack / Browserify hanya dapat dibangun di CommonJS. Keuntungan besar IIFE adalah kekompakan dan tidak adanya konflik antara versi CommonJS yang berbeda. Tetapi ada satu kelemahan, Anda tidak dapat mengumpulkan bongkahan, untuk itu Anda harus beralih ke CommonJS.

Kompilasi dalam ES2015


Nama "rollup generasi berikutnya" yang diterima pada tahun 2016 diterima karena kemampuan untuk berkumpul di ES2015. Dan hingga akhir 2018, satu-satunya kolektor yang tahu bagaimana melakukan ini.
Misalnya, jika Anda mengambil kode:

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

dan melewati Rollup, lalu pada output kita mendapatkan hal yang sama. Dan ya! Pada awal 2019, sudah 87% browser dapat menjalankannya secara asli.

Kemudian pada tahun 2016 itu tampak seperti terobosan, karena ada sejumlah besar aplikasi yang tidak memerlukan dukungan untuk browser lama: admin, kios, bukan aplikasi web, dan tidak ada alat membangun untuk mereka. Dan sekarang dengan Rollup kita dapat mengumpulkan beberapa bundel dalam satu pass, di es3, es5, es2015, exnext dan tergantung pada unduhan browser yang diperlukan.

Keunggulan besar ES2015 adalah ukuran dan kecepatan eksekusi. Karena kurangnya transpiling ke lapisan bawah, kode ini ternyata jauh lebih ringkas, dan karena kurangnya kode bantu yang dihasilkan oleh transpiler, kode ini juga berfungsi 3 kali lebih cepat (menurut tes subjektif saya).

Pohon bergetar


Ini adalah chip Rollup, ia menciptakannya! Webpack telah mencoba mengimplementasikannya selama bertahun-tahun berturut-turut, tetapi hanya dengan versi 4 sesuatu mulai bekerja. Browserify melakukannya dengan sangat buruk.
Hewan apa ini? Mari kita ambil dua file berikut sebagai contoh:

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

jalankan melalui Rollup dan dapatkan:

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

Sebagai hasil dari TreeShaking, kode mati dibuang bahkan pada tahap penyelesaian dependensi. Berkat majelis Rollup ternyata jauh lebih kompak. Sekarang mari kita lihat apa yang dihasilkan Webpack:

Hasil pembuatan 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()); /***/ }) /******/ ]); 


Dan di sini kita dapat menarik dua kesimpulan. Webpack pertama pada akhir 2018 masih belajar untuk memahami dan membangun ES2015. Yang kedua, benar-benar semua kode termasuk dalam rakitan, tetapi kode mati sudah dihapus menggunakan minifier Terser (fork dan penerus UglifyES). Sebagai hasil dari pendekatan ini, bundel lebih tebal dari Rollup, pada habr sudah menulis banyak tentang itu, kami tidak akan berhenti di situ.

Plugin


Hanya ES2015 + telanjang yang dapat dirakit dari kotak Rollup. Untuk mengajarinya fungsionalitas tambahan, seperti menghubungkan commonjs, modul naskah, memuat html dan scss, dll., Anda perlu menghubungkan plugin.

Ini dilakukan dengan sangat sederhana:
 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() //   ] }]; 

Sangat sederhana, satu plug-in terhubung dalam satu kata. Konfigurasi ini dapat mengumpulkan aplikasi yang kompleks dan bahkan menghasilkan analisis bundel pada output.

Ringkasan


Dan sekarang, dipersenjatai dengan pengetahuan baru, mari kita membuat konfigurasi yang akan mengumpulkan polifile secara terpisah, aplikasi terpisah untuk browser lama dan baru, seorang pekerja layanan untuk pwa, dan seorang pekerja web untuk perhitungan kompleks di brounund.

 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" }) }]; 


Semua bundel mudah dan aplikasi web cepat!

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


All Articles