您现在的位置是:亿华云 > IT科技类资讯

Web Bundler CheatSheet, 选择合适的构建打包工具

亿华云2025-10-02 19:02:18【IT科技类资讯】5人已围观

简介Web Bundler CheatSheet | Web 构建与打包工具盘点工欲善其事,必先利其器,当我们准备开始某个 Web 相关的项目时,合适的脚手架会让我们事半功倍。在 2016-我的前端之路:

Web Bundler CheatSheet | Web 构建与打包工具盘点

工欲善其事,选择必先利其器,合适当我们准备开始某个 Web 相关的建打具项目时,合适的包工脚手架会让我们事半功倍。在 2016-我的选择前端之路:工具化与工程化一文中,我们讨论了工具化与工程化相关的合适内容,其中重要的建打具章节就是关于所谓的打包工具。Grunt、包工Glup 属于 Task Runner,选择即任务执行器; 实际上,合适npm package.json 中定义的建打具脚本也可以看做 Task Runner,而 Rollup,包工Parcel 以及 Webpack 则是选择属于 Bundler,即打包工具。合适

尺有所短,建打具寸有所长,不同的构建工具有其不同的适用场景。Webpack 是非常优秀的构建与打包工具,但是其提供了基础且复杂的功能支持,服务器租用使得并不适用于全部的场景。Parcel 这样的零配置打包工具适合于应用型的原型项目构建,而 Rollup 或者 Microbundle 适合于库的打包,Backpack 则能够帮我们快速构建 Node.js 项目。笔者在本文中列举讨论的仅是日常工作中会使用的工具,更多的 Browserify、Fusebox 等等构建工具查看 Web 构建与打包工具资料索引或者现代 Web 开发实战/进阶篇。

Parcel

Parcel 是著名的零配置的应用打包工具,在 TensorflowJS 或者 gh-craft 等算法实验/游戏场景构建中,都能够快速地搭建应用。

# 安装 Parcel $ npm install -g parcel-bundler # 启动开发服务器 $ parcel index.html # 执行线上编译 $ parcel build index.js # 指定编译路径 $ parcel build index.js -d build/output 

Parcel 会为我们自动地下载安装依赖,并且内置了 ES、SCSS 等常见的处理器。在 fe-boilerplate 中提供了 React, React & TypeScript, Vue.js 等 Parcel 常见的示例,这里以 React 为例,首先定义组件与渲染:

// index.js import React from react; import ReactDOM from react-dom; import logo from ../public/logo.svg; import ./index.css; const App = () => (   <div className="App">     <img className="App-Logo" src={ logo} alt="React Logo" />     <h1 className="App-Title">Hello Parcel x React</h1>   </div> ); ReactDOM.render(<App />, document.getElementById(root)); // Hot Module Replacement if (module.hot) {    module.hot.accept(); } 

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

<html lang="en"> <head>   <meta charset="UTF-8">   <meta name="viewport" content="width=device-width, initial-scale=1.0">   <meta http-equiv="X-UA-Compatible" content="ie=edge">   <title>Parcel React Example</title> </head> <body>   <div id="root"></div>   <script src="./index.js"></script> </body> </html> 

然后使用 parcel index.html 运行开发服务器即可。Parcel 中同样也是支持异步加载的,高防服务器假设我们将部分代码定义在 someModule.js 文件中,然后在用户真实需要时再进行加载:

// someModule.js console.log(someModule.js loaded); module.exports = {    render: function(element) {      element.innerHTML = You clicked a button;   } }; 

在入口文件中使用 import 进行异步加载:

console.log(index.js loaded); window.onload = function() {    document.querySelector(#bt).addEventListener(click, function(evt) {      console.log(Button Clicked);     import(./someModule).then(function(page) {        page.render(document.querySelector(.holder));     });   }); }; 

***值得一提的是,Parcel 内建支持 WebAssembly 与 Rust,通过简单的 import 导入,即可以使用 WASM 模块:

// synchronous import import { add} from ./add.wasm; console.log(add(2, 3)); // asynchronous import const { add} = await import(./add.wasm); console.log(add(2, 3)); // synchronous import import { add} from ./add.rs; console.log(add(2, 3)); // asynchronous import const { add} = await import(./add.rs); console.log(add(2, 3)); 

这里 add.rs 是使用 Rust 编写的简单加法计算函数:

#[no_mangle] pub fn add(a: i32, b: i32) -> i32 {    return a + b } 

Rollup 是较为为纯粹的模块打包工具,其相较于 Parcel 与 Webpack 等,更适合于构建 Library,譬如 React、Vue.js、Angular、D3、Moment、Redux 等一系列优秀的库都是采用 Rollup 进行构建。。Rollup 能够将按照 ESM(ES2015 Module)规范编写的源码构建输出为 IIFE、AMD、CommonJS、UMD、ESM 等多种格式,并且其较早地支持 Tree Shaking,Scope Hoisting 等优化特性,保证模块的简洁与高效。云南idc服务商这里我们使用的 Rollup 示例配置项目存放在了 fe-boilerplate/rollup。最简单的 rollup.config.js 文件配置如下:

export default {    // 指定模块入口   entry: src/scripts/main.js,   // 指定包体文件名   dest: build/js/main.min.js,   // 指定文件格式   format: iife,   // 指定 SourceMap 格式   sourceMap: inline }; 

如果我们只是对简单的 sayHello 函数进行打包,那么输出的文件中也只是会简单地连接与调用,并且清除未真实使用的模块:

(function() {    use strict;   ...   function sayHelloTo(name) {      ...   }   ...   const result1 = sayHelloTo(Jason);   ... })(); //# sourceMappingURL=data:application/json;charset=utf-8;base64,... 

Rollup 同样具有丰富的插件系统,在 fe-boilerplate/rollup 中我们也引入了常见的别名、ESLint、环境变量定义、包体压缩与分析等插件。这里我们以最常用的 Babel 与 TypeScript 为例,如果我们需要在项目中引入 Babel,则同样在根目录配置 .babelrc 文件,然后引入 rollup-plugin-babel 插件即可:

import {  rollup } from rollup; import babel from rollup-plugin-babel; rollup({    entry: main.js,   plugins: [     babel({        exclude: node_modules/**     })   ] }).then(...) 

对于 TypeScript 则是引入 rollup-plugin-typescript 插件:

import typescript from rollup-plugin-typescript; export default {    entry: ./main.ts,   plugins: [typescript()] }; 

Microbundle 则是 Developit 基于 Rollup 封装的零配置的轻量级打包工具,其目前已经内建支持 TypeScript 与 Flow,不需要额外的配置;笔者在 js-swissgear/x-fetch 项目的打包中也使用了该工具。

{    "scripts": {      "build": "microbundle",     "dev": "microbundle watch"   } }  index.js 是 CommonJS 模块,是 Node.js 内置的模块类型,使用类似于 require(MyModule) 语法导入 index.m.js 是 ECMAScript 模块,使用类似于 import MyModule from my-module 语法导入 index.umd.js 是 UMD 模块 index.d.ts 是 TypeScript 的类型声明文件

Webpack

作为著名的打包工具,Webpack 允许我们指定项目的入口地址,然后自动将用到的资源,经由 Loader 与 Plugin 的转换,打包到包体文件中。Webpack 相关的项目模板可以参考:fe-boilerplate/react-webpack, fe-boilerplate/react-webpack-ts, fe-boilerplate/vue-webpack 等。

Webpack 目前也支持零配置运行

$ npm install webpack webpack-cli webpack-dev-server --save-dev "scripts": {    "start": "webpack-dev-server --mode development",   "build": "webpack --mode production" }, 

基础配置

const config = {    // 定义入口   entry: {      app: path.join(__dirname, app)   },   // 定义包体文件   output: {      // 输出目录     path: path.join(__dirname, build),     // 输出文件名     filename: [name].js     // 使用 hash 作为文件名     // filename: "[name].[chunkhash].js",   },   // 定义如何处理   module: {      rules: [       {          test: /\.js$/,         use: babel-loader,         exclude: /node_modules/       }     ]   },   // 添加额外插件操作   plugins: [new webpack.DefinePlugin()] }; 

Webpack 同样支持添加多个配置:

module.exports = [{    entry: ./app.js,   output: ...,   ... }, {    entry: ./app.js,   output: ...,   ... }] 

我们代码中的 require 与 import 解析规范,则由 resolve 模块负责,其包含了扩展、别名、模块等部分:

const config = {    resolve: {      alias: {        /*...*/     },     extensions: [       /*...*/     ],     modules: [       /*...*/     ]   } }; 

资源加载

const config = {    module: {      rules: [       {          // **Conditions**         test: /\.js$/, // Match files         enforce: pre, // "post" too         // **Restrictions**         include: path.join(__dirname, app),         exclude: path => path.match(/node_modules/),         // **Actions**         use: babel-loader       }     ]   } }; // Process foo.png through url-loader and other matches import url-loader!./foo.png; // Override possible higher level match completely import !!url-loader!./bar.png; 

babel-loader 或者 awesome-typescript-loader 来处理 JavaScript 或者 TypeScript 文件

/

很赞哦!(8533)