自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Web Bundler CheatSheet, 選擇合適的構(gòu)建打包工具

開(kāi)發(fā) 開(kāi)發(fā)工具
工欲善其事,必先利其器,當(dāng)我們準(zhǔn)備開(kāi)始某個(gè) Web 相關(guān)的項(xiàng)目時(shí),合適的腳手架會(huì)讓我們事半功倍。在 2016-我的前端之路:工具化與工程化一文中,我們討論了工具化與工程化相關(guān)的內(nèi)容,其中重要的章節(jié)就是關(guān)于所謂的打包工具。

Web Bundler CheatSheet | Web 構(gòu)建與打包工具盤(pán)點(diǎn)

工欲善其事,必先利其器,當(dāng)我們準(zhǔn)備開(kāi)始某個(gè) Web 相關(guān)的項(xiàng)目時(shí),合適的腳手架會(huì)讓我們事半功倍。在 2016-我的前端之路:工具化與工程化一文中,我們討論了工具化與工程化相關(guān)的內(nèi)容,其中重要的章節(jié)就是關(guān)于所謂的打包工具。Grunt、Glup 屬于 Task Runner,即任務(wù)執(zhí)行器; 實(shí)際上,npm package.json 中定義的腳本也可以看做 Task Runner,而 Rollup,Parcel 以及 Webpack 則是屬于 Bundler,即打包工具。

尺有所短,寸有所長(zhǎng),不同的構(gòu)建工具有其不同的適用場(chǎng)景。Webpack 是非常優(yōu)秀的構(gòu)建與打包工具,但是其提供了基礎(chǔ)且復(fù)雜的功能支持,使得并不適用于全部的場(chǎng)景。Parcel 這樣的零配置打包工具適合于應(yīng)用型的原型項(xiàng)目構(gòu)建,而 Rollup 或者 Microbundle 適合于庫(kù)的打包,Backpack 則能夠幫我們快速構(gòu)建 Node.js 項(xiàng)目。筆者在本文中列舉討論的僅是日常工作中會(huì)使用的工具,更多的 Browserify、Fusebox 等等構(gòu)建工具查看 Web 構(gòu)建與打包工具資料索引或者現(xiàn)代 Web 開(kāi)發(fā)實(shí)戰(zhàn)/進(jìn)階篇。

Parcel

Parcel 是著名的零配置的應(yīng)用打包工具,在 TensorflowJS 或者 gh-craft 等算法實(shí)驗(yàn)/游戲場(chǎng)景構(gòu)建中,都能夠快速地搭建應(yīng)用。

  1. # 安裝 Parcel 
  2. $ npm install -g parcel-bundler 
  3.  
  4. # 啟動(dòng)開(kāi)發(fā)服務(wù)器 
  5. $ parcel index.html 
  6.  
  7. # 執(zhí)行線上編譯 
  8. $ parcel build index.js 
  9.  
  10. # 指定編譯路徑 
  11. $ parcel build index.js -d build/output 

Parcel 會(huì)為我們自動(dòng)地下載安裝依賴,并且內(nèi)置了 ES、SCSS 等常見(jiàn)的處理器。在 fe-boilerplate 中提供了 React, React & TypeScript, Vue.js 等 Parcel 常見(jiàn)的示例,這里以 React 為例,首先定義組件與渲染:

  1. // index.js 
  2. import React from 'react'
  3. import ReactDOM from 'react-dom'
  4. import logo from '../public/logo.svg'
  5. import './index.css'
  6.  
  7. const App = () => ( 
  8.   <div className="App"
  9.     <img className="App-Logo" src={logo} alt="React Logo" /> 
  10.     <h1 className="App-Title">Hello Parcel x React</h1> 
  11.   </div> 
  12. ); 
  13.  
  14. ReactDOM.render(<App />, document.getElementById('root')); 
  15.  
  16. // Hot Module Replacement 
  17. if (module.hot) { 
  18.   module.hot.accept(); 

然后定義入口的 index.html 文件:

  1. <html lang="en"
  2.  
  3. <head> 
  4.   <meta charset="UTF-8"
  5.   <meta name="viewport" content="width=device-width, initial-scale=1.0"
  6.   <meta http-equiv="X-UA-Compatible" content="ie=edge"
  7.   <title>Parcel React Example</title> 
  8.  
  9. </head> 
  10.  
  11. <body> 
  12.   <div id="root"></div> 
  13.   <script src="./index.js"></script> 
  14. </body> 
  15.  
  16. </html> 

然后使用 parcel index.html 運(yùn)行開(kāi)發(fā)服務(wù)器即可。Parcel 中同樣也是支持異步加載的,假設(shè)我們將部分代碼定義在 someModule.js 文件中,然后在用戶真實(shí)需要時(shí)再進(jìn)行加載:

  1. // someModule.js 
  2. console.log('someModule.js loaded'); 
  3. module.exports = { 
  4.   render: function(element) { 
  5.     element.innerHTML = 'You clicked a button'
  6.   } 
  7. }; 

在入口文件中使用 import 進(jìn)行異步加載:

  1. console.log('index.js loaded'); 
  2. window.onload = function() { 
  3.   document.querySelector('#bt').addEventListener('click'function(evt) { 
  4.     console.log('Button Clicked'); 
  5.     import('./someModule').then(function(page) { 
  6.       page.render(document.querySelector('.holder')); 
  7.     }); 
  8.   }); 
  9. }; 

***值得一提的是,Parcel 內(nèi)建支持 WebAssembly 與 Rust,通過(guò)簡(jiǎn)單的 import 導(dǎo)入,即可以使用 WASM 模塊:

  1. // synchronous import 
  2. import {addfrom './add.wasm'
  3. console.log(add(2, 3)); 
  4.  
  5. // asynchronous import 
  6. const {add} = await import('./add.wasm'); 
  7. console.log(add(2, 3)); 
  8.  
  9. // synchronous import 
  10. import {addfrom './add.rs'
  11. console.log(add(2, 3)); 
  12.  
  13. // asynchronous import 
  14. const {add} = await import('./add.rs'); 
  15. console.log(add(2, 3)); 

這里 add.rs 是使用 Rust 編寫(xiě)的簡(jiǎn)單加法計(jì)算函數(shù):

  1. #[no_mangle] 
  2. pub fn add(a: i32, b: i32) -> i32 { 
  3.   return a + b 

Rollup 是較為為純粹的模塊打包工具,其相較于 Parcel 與 Webpack 等,更適合于構(gòu)建 Library,譬如 React、Vue.js、Angular、D3、Moment、Redux 等一系列優(yōu)秀的庫(kù)都是采用 Rollup 進(jìn)行構(gòu)建。。Rollup 能夠?qū)凑?ESM(ES2015 Module)規(guī)范編寫(xiě)的源碼構(gòu)建輸出為 IIFE、AMD、CommonJS、UMD、ESM 等多種格式,并且其較早地支持 Tree Shaking,Scope Hoisting 等優(yōu)化特性,保證模塊的簡(jiǎn)潔與高效。這里我們使用的 Rollup 示例配置項(xiàng)目存放在了 fe-boilerplate/rollup。最簡(jiǎn)單的 rollup.config.js 文件配置如下:

  1. export default { 
  2.   // 指定模塊入口 
  3.   entry: 'src/scripts/main.js'
  4.   // 指定包體文件名 
  5.   dest: 'build/js/main.min.js'
  6.   // 指定文件格式 
  7.   format: 'iife'
  8.   // 指定 SourceMap 格式 
  9.   sourceMap: 'inline' 
  10. }; 

如果我們只是對(duì)簡(jiǎn)單的 sayHello 函數(shù)進(jìn)行打包,那么輸出的文件中也只是會(huì)簡(jiǎn)單地連接與調(diào)用,并且清除未真實(shí)使用的模塊:

  1. (function() { 
  2.   'use strict'
  3.   ... 
  4.   function sayHelloTo(name) { 
  5.     ... 
  6.   } 
  7.   ... 
  8.   const result1 = sayHelloTo('Jason'); 
  9.   ... 
  10. })(); 
  11. //# sourceMappingURL=data:application/json;charset=utf-8;base64,... 

Rollup 同樣具有豐富的插件系統(tǒng),在 fe-boilerplate/rollup 中我們也引入了常見(jiàn)的別名、ESLint、環(huán)境變量定義、包體壓縮與分析等插件。這里我們以最常用的 Babel 與 TypeScript 為例,如果我們需要在項(xiàng)目中引入 Babel,則同樣在根目錄配置 .babelrc 文件,然后引入 rollup-plugin-babel 插件即可:

  1. import { rollup } from 'rollup'
  2. import babel from 'rollup-plugin-babel'
  3.  
  4. rollup({ 
  5.   entry: 'main.js'
  6.   plugins: [ 
  7.     babel({ 
  8.       exclude: 'node_modules/**' 
  9.     }) 
  10.   ] 
  11. }).then(...) 

對(duì)于 TypeScript 則是引入 rollup-plugin-typescript 插件:

  1. import typescript from 'rollup-plugin-typescript'
  2.  
  3. export default { 
  4.   entry: './main.ts'
  5.  
  6.   plugins: [typescript()] 
  7. }; 

Microbundle 則是 Developit 基于 Rollup 封裝的零配置的輕量級(jí)打包工具,其目前已經(jīng)內(nèi)建支持 TypeScript 與 Flow,不需要額外的配置;筆者在 js-swissgear/x-fetch 項(xiàng)目的打包中也使用了該工具。

  1.   "scripts": { 
  2.     "build""microbundle"
  3.     "dev""microbundle watch" 
  4.   } 
  • index.js 是 CommonJS 模塊,是 Node.js 內(nèi)置的模塊類型,使用類似于 require('MyModule') 語(yǔ)法導(dǎo)入
  • index.m.js 是 ECMAScript 模塊,使用類似于 import MyModule from 'my-module' 語(yǔ)法導(dǎo)入
  • index.umd.js 是 UMD 模塊
  • index.d.ts 是 TypeScript 的類型聲明文件

Webpack

作為著名的打包工具,Webpack 允許我們指定項(xiàng)目的入口地址,然后自動(dòng)將用到的資源,經(jīng)由 Loader 與 Plugin 的轉(zhuǎn)換,打包到包體文件中。Webpack 相關(guān)的項(xiàng)目模板可以參考:fe-boilerplate/react-webpack, fe-boilerplate/react-webpack-ts, fe-boilerplate/vue-webpack 等。

Webpack 目前也支持零配置運(yùn)行

  1. $ npm install webpack webpack-cli webpack-dev-server --save-dev 
  2. "scripts": { 
  3.   "start""webpack-dev-server --mode development"
  4.   "build""webpack --mode production" 
  5. }, 

基礎(chǔ)配置

  1. const config = { 
  2.   // 定義入口 
  3.   entry: { 
  4.     app: path.join(__dirname, 'app'
  5.   }, 
  6.   // 定義包體文件 
  7.   output: { 
  8.     // 輸出目錄 
  9.     path: path.join(__dirname, 'build'), 
  10.  
  11.     // 輸出文件名 
  12.     filename: '[name].js' 
  13.     // 使用 hash 作為文件名 
  14.     // filename: "[name].[chunkhash].js"
  15.   }, 
  16.   // 定義如何處理 
  17.   module: { 
  18.     rules: [ 
  19.       { 
  20.         test: /\.js$/, 
  21.         use: 'babel-loader'
  22.         exclude: /node_modules/ 
  23.       } 
  24.     ] 
  25.   }, 
  26.   // 添加額外插件操作 
  27.   plugins: [new webpack.DefinePlugin()] 
  28. }; 

Webpack 同樣支持添加多個(gè)配置:

  1. module.exports = [{ 
  2.   entry: './app.js'
  3.   output: ..., 
  4.   ... 
  5. }, { 
  6.   entry: './app.js'
  7.   output: ..., 
  8.   ... 
  9. }] 

我們代碼中的 require 與 import 解析規(guī)范,則由 resolve 模塊負(fù)責(zé),其包含了擴(kuò)展、別名、模塊等部分:

  1. const config = { 
  2.   resolve: { 
  3.     alias: { 
  4.       /*...*/ 
  5.     }, 
  6.     extensions: [ 
  7.       /*...*/ 
  8.     ], 
  9.     modules: [ 
  10.       /*...*/ 
  11.     ] 
  12.   } 
  13. }; 

資源加載

  1. const config = { 
  2.   module: { 
  3.     rules: [ 
  4.       { 
  5.         // **Conditions** 
  6.         test: /\.js$/, // Match files 
  7.         enforce: 'pre', // "post" too 
  8.  
  9.         // **Restrictions** 
  10.         include: path.join(__dirname, 'app'), 
  11.         exclude: path => path.match(/node_modules/), 
  12.  
  13.         // **Actions** 
  14.         use: 'babel-loader' 
  15.       } 
  16.     ] 
  17.   } 
  18. }; 
  19. // Process foo.png through url-loader and other matches 
  20. import 'url-loader!./foo.png'
  21.  
  22. // Override possible higher level match completely 
  23. import '!!url-loader!./bar.png'

babel-loader 或者 awesome-typescript-loader 來(lái)處理 JavaScript 或者 TypeScript 文件

  1. /******/ (function(modules) { // webpackBootstrap 
  2. ... 
  3. /* 0 */ 
  4. /***/ (function(module, __webpack_exports__, __webpack_require__) { 
  5.  
  6. "use strict"
  7. __webpack_require__.r(__webpack_exports__); 
  8. /* harmony default export */ __webpack_exports__["default"] = ((text = "Hello world") => { 
  9.   const element = document.createElement("div"); 
  10.  
  11.   element.innerHTML = text; 
  12.  
  13.   return element; 
  14. }); 
  15.  
  16. /***/ }) 
  17. /******/ ]); 

use: ["style-loader", "css-loader"] css-loader 會(huì)自動(dòng)地解析 @import 與 url(),而 style-loader 則會(huì)將 CSS 注入到 DOM 中,并且實(shí)現(xiàn) HMR 的特性,而對(duì)于 SASS、LESS 等 CSS 預(yù)處理器,也有專門(mén)的 sass-loader 或者 less-loader 來(lái)處理;在生產(chǎn)環(huán)境下,我們也常常會(huì)將 CSS 抽取到獨(dú)立的樣式文件中,此時(shí)就可以使用 mini-css-extract-plugin (MCEP) 等工具。同樣,我們可以使用 url-loader/file-loader 來(lái)處理圖片等資源文件,

代碼分割

代碼分割是提升 Web 性能表現(xiàn)的重要分割,我們常做的代碼分割也分為公共代碼提取與按需加載等方式。公共代碼提取即是將第三方渲染模塊或者庫(kù)與應(yīng)用本身的邏輯代碼分割,或者將應(yīng)用中多個(gè)模塊間的公共代碼提取出來(lái),劃分到獨(dú)立的 Chunk 中,以方便客戶端進(jìn)行緩存等操作。

[[231069]]

不同于 Webpack 3 中需要依賴 CommonChunksPlugin 進(jìn)行配置,Webpack 4 引入了 SplitChunksPlugin,并為我們提供了開(kāi)箱即用的代碼優(yōu)化特性,Webpack 會(huì)根據(jù)以下情況自動(dòng)進(jìn)行代碼分割操作:

  • 新的塊是在多個(gè)模塊間共享,或者來(lái)自于 node_modules 目錄;
  • 新的塊在壓縮之前的大小應(yīng)該超過(guò) 30KB;
  • 頁(yè)面所需并發(fā)加載的塊數(shù)量應(yīng)該小于或者等于 5;
  • 初始頁(yè)面加載的塊數(shù)量應(yīng)該小于或者等于 3;

SplitChunksPlugin 的默認(rèn)配置如下:

  1. splitChunks: { 
  2.     chunks: "async"
  3.     minSize: 30000, 
  4.     minChunks: 1, 
  5.     maxAsyncRequests: 5, 
  6.     maxInitialRequests: 3, 
  7.     automaticNameDelimiter: '~'
  8.     nametrue
  9.     cacheGroups: { 
  10.         vendors: { 
  11.             test: /[\\/]node_modules[\\/]/, 
  12.             priority: -10 
  13.         }, 
  14.     default: { 
  15.             minChunks: 2, 
  16.             priority: -20, 
  17.             reuseExistingChunk: true 
  18.         } 
  19.     } 

值得一提的是,這里的 chunks 選項(xiàng)有 initial, async 與 all 三個(gè)配置,上述配置即是分別針對(duì)初始 chunks、按需加載的 chunks 與全部的 chunks 進(jìn)行優(yōu)化;如果將 vendors 的 chunks 設(shè)置為 initial,那么它將忽略通過(guò)動(dòng)態(tài)導(dǎo)入的模塊包包含的第三方庫(kù)代碼。而 priority 則用于指定某個(gè)自定義的 Cache Group 捕獲代碼的優(yōu)先級(jí),其默認(rèn)值為 0。在 common-chunk-and-vendor-chunk 例子中,我們即針對(duì)入口進(jìn)行優(yōu)化,提取出入口公共的 vendor 模塊與業(yè)務(wù)模塊:

  1. splitChunks: { 
  2.             cacheGroups: { 
  3.                 commons: { 
  4.                     chunks: "initial"
  5.                     minChunks: 2, 
  6.                     maxInitialRequests: 5, // The default limit is too small to showcase the effect 
  7.                     minSize: 0 // This is example is too small to create commons chunks 
  8.                 }, 
  9.                 vendor: { 
  10.                     test: /node_modules/, 
  11.                     chunks: "initial"
  12.                     name"vendor"
  13.                     priority: 10, 
  14.                     enforce: true 
  15.                 } 
  16.             } 
  17.         } 

Webpack 的 optimization 還包含了 runtimeChunk 屬性,當(dāng)該屬性值被設(shè)置為 true 時(shí),即會(huì)為每個(gè) Entry 添加僅包含運(yùn)行時(shí)信息的 Chunk; 當(dāng)該屬性值被設(shè)置為 single 時(shí),即為所有的 Entry 創(chuàng)建公用的包含運(yùn)行時(shí)的 Chunk。我們也可以在代碼中使用 import 語(yǔ)句,動(dòng)態(tài)地進(jìn)行塊劃分,實(shí)現(xiàn)代碼的按需加載:

  1. // Webpack 3 之后支持顯式指定 Chunk 名 
  2. import(/* webpackChunkName: "optional-name" */ './module'
  3.   .then(module => { 
  4.     /* ... */ 
  5.   }) 
  6.   .catch(error => { 
  7.     /* ... */ 
  8.   }); 
  9. webpackJsonp([0], { 
  10.   KMic: function(a, b, c) { 
  11.     ... 
  12.   }, 
  13.   co9Y: function(a, b, c) { 
  14.     ... 
  15.   }, 
  16. }); 

如果是使用 React 進(jìn)行項(xiàng)目開(kāi)發(fā),推薦使用 react-loadable 進(jìn)行組件的按需加載,他能夠優(yōu)雅地處理組件加載、服務(wù)端渲染等場(chǎng)景。Webpack 還內(nèi)建支持基于 ES6 Module 規(guī)范的 Tree Shaking 優(yōu)化,即僅從導(dǎo)入文件中提取出所需要的代碼。

更多關(guān)于 Webpack 的使用技巧可以參閱 Webpack CheatSheet 或者現(xiàn)代 Web 開(kāi)發(fā)基礎(chǔ)與工程實(shí)踐/Webpack 章節(jié)。

Backpack

Backpack 是面向 Node.js 的極簡(jiǎn)構(gòu)建系統(tǒng),受 create-react-app, Next.js 以及 Nodemon 的影響,能夠以零配置的方式創(chuàng)建 Node.js 項(xiàng)目。Backpack 為我們處理了文件監(jiān)控、熱加載、轉(zhuǎn)換、打包等工作,默認(rèn)支持 ECMAScript ***的 async/await, 對(duì)象擴(kuò)展、類屬性等語(yǔ)法。我們可以使用 npm 安裝依賴:

  1. $ npm i backpack-core --save 

然后在 package.json 中配置運(yùn)行腳本:

  1.   "scripts": { 
  2.     "dev""backpack"
  3.     "build""backpack build" 
  4.   } 

在 Backend-Boilerplate/node 中可以查看 Backpack 的典型應(yīng)用,我們也可以覆蓋默認(rèn)的 Webpack 配置:

  1. // backpack.config.js 
  2. module.exports = { 
  3.   webpack: (config, options, webpack) => { 
  4.     // Perform customizations to config 
  5.     // Important: return the modified config 
  6.     return config; 
  7.   } 
  8. }; 

或者添加 Babel 插件:

  1.   "presets": ["backpack-core/babel""stage-0"

 【本文是51CTO專欄作者“張梓雄 ”的原創(chuàng)文章,如需轉(zhuǎn)載請(qǐng)通過(guò)51CTO與作者聯(lián)系】

戳這里,看該作者更多好文

責(zé)任編輯:武曉燕 來(lái)源: 51CTO專欄
相關(guān)推薦

2021-12-25 22:29:04

WebpackRollup 前端

2020-12-23 10:30:50

Web安全截包工具服務(wù)器

2010-08-20 13:47:11

BlackBerry應(yīng)BlackBerry

2023-10-16 07:42:10

前端構(gòu)建高性能

2023-12-04 07:14:40

通信微服務(wù)

2016-10-08 18:13:55

數(shù)據(jù)庫(kù)性能工具數(shù)據(jù)庫(kù)管理系統(tǒng)

2017-06-19 16:20:09

數(shù)據(jù)庫(kù)性能工具

2010-06-08 15:44:18

UML建模工具

2024-09-02 00:00:01

2024-03-11 00:02:00

Vite開(kāi)源工具

2010-12-13 09:21:00

2025-03-04 07:40:00

Python模塊開(kāi)發(fā)

2022-05-30 11:21:25

數(shù)據(jù)庫(kù)MySQL工具

2022-06-14 08:00:00

JavaScript工具Metro

2021-01-10 15:29:53

開(kāi)源數(shù)據(jù)庫(kù)數(shù)據(jù)庫(kù)

2022-02-07 08:58:54

DCIM數(shù)據(jù)中心

2023-05-29 15:53:32

DevOps架構(gòu)自動(dòng)化

2014-12-09 12:57:19

AnySDK

2015-11-23 17:12:53

數(shù)據(jù)中心CMDB工具

2019-03-11 15:48:13

企業(yè)存儲(chǔ)數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)