1

使用 Rollup 打包 Angular 应用

 2 years ago
source link: https://beginor.github.io/2021/10/17/bundle-angular-apps-with-rollup.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

使用 Rollup 打包 Angular 应用

Rollup 简介

rollup.js

Rollup 是一个 JavaScript 模块打包器, 可以将小块代码编译成大块复杂的代码, 例如类库或应用程序。 Rollup 使用 JavaScript 标准的 ES6 模块, 而不是以前的 CommonJS 或者 AMD 模块。 和 Webpack 相比, Rollup 一个显著的优势是可以输出 ES6 模块,非常的简洁, 现代化的浏览器都可以直接加载, 跨项目重用也非常的方便。 而 Webpack 的输出则必须的依赖晦涩的 Webpack 运行时, 同时也很难跨项目重用。

Rollup 也是非常的流行, npm 上 大部分 JavaScript 类库都在使用它进行打包。 但是使用 Rollup 打包应用的似乎不太多,因此本文就介绍一下如何使用 Rollup 来打包一个典型的 Angular 应用。

创建 Angular 应用

要创建 Angular 应用,首选还是 angular-cli , 因为 Angular 应用和 React/Vue 比起来还是稍微复杂一些, 打开终端, 输入下面的命令:

npx @angular/cli@latest new rollup-angular --skip-git --minimal \
  --style scss --routing true --skip-tests true

等待命令安装完成之后, 再输入 npx ng serve --configuration development , 打开浏览器访问 http://localhost:4200 , 可以看到如下的界面:

image-20211016115154405

现在 Angular 应用就创建好了, 接下来就是进行一些预处理, 以便使用 Rollup 来对它进行打包。

预处理 Angular 应用

  • 使用 ivy 视图引擎预处理全部的 Angular 类库

    在终端中输入命令 npx ngcc , 这个命令会查找位于 node_modules 目录下的所有 Angular 相关的类库并使用 ivy 视图引擎进行预处理, 可以看到类似下面的输出:

    Compiling @angular/core : fesm2015 as esm2015
    Compiling @angular/animations : fesm2015 as esm2015
    Compiling @angular/compiler/testing : fesm2015 as esm2015
    Compiling @angular/animations : esm2015 as esm2015
    Compiling @angular/animations : main as umd
    Compiling @angular/compiler/testing : esm2015 as esm2015
    Compiling @angular/compiler/testing : main as umd
    Compiling @angular/animations/browser : fesm2015 as esm2015
    
  • 在 Angular 应用中强制使用 ivy 视图引擎

    打开 src/main.ts 做如下修改:

    - import { enableProdMode } from '@angular/core';
    + import { enableProdMode, ɵNgModuleFactory as NgModuleFactory } from '@angular/core';
    - import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
    + import { platformBrowser } from '@angular/platform-browser';
      
    import { AppModule } from './app/app.module';
    import { environment } from './environments/environment';
      
    if (environment.production) {
      enableProdMode();
    }
      
    - platformBrowserDynamic().bootstrapModule(AppModule)
    + platformBrowser().bootstrapModuleFactory(new NgModuleFactory(AppModule))
      .catch(err => console.error(err));
      
    

    注意 ɵNgModuleFactory 只有在 ngcc 命令处理过之后才会出现。

使用 ngc 编译 Angular 应用

Angular 应用虽然是使用 TypeScript 进行编写, 但是却不能直接使用 TypeScript 的 tsc 命令进行编译, 而必需使用 angular-cli 的 ngc 命令进行编译, 使用 ngc 编译的命令参数和 tsc 基本一致:

npx ngc -p tsconfig.app.json

输出结果在 out-tsc 目录下, 入口文件有两个, 分别是 out-tsc/app/main.jsout-tsc/app/polyfills.js , 接下来就可以使用 Rollup 进行打包了。

如果当前工作区有多个 angular 项目的话, 可以修改对应的 tsconfig.app.json 文件, 自定义 ngc 的输出结果。

Angular 类库项目的编译

如果工作区中存在 Angular 类库项目, 则可以直接使用 angular-cli 的 ng 命令进行编译, 命令如下:

npx ng build app-shared --configuration=development

注意的是,一定要指定 --configuration=development 才能得到完整兼容 Ivy 视图引擎的输出, 如果不指定则默认的配置是 production,无法得到完整兼容 Ivy 视图引擎的输出 。

安装 Rollup 及配套插件

要用 Rollup 来打包上面的 Angular 应用, 需要安装 Rollup 以及对应的插件,说明如下:

  • rollup 这个是 rollup 本尊, 自然不必多说;
  • @rollup/plugin-alias 如果项目中用到了 Angular 类库项目, 可以用 alias 来指定别名;
  • @rollup/plugin-commonjs 使用到的第三方类库有可能是 commonjs 模块化的, 这个插件可以讲 commonjs 模块转换为 ES6 模块;
  • @rollup/plugin-node-resolve 这个插件负责从 node_modules 目录中查找模块;
  • rollup-plugin-scss 以及 sass 因为用到了 scss 作为样式, 所以需要这个插件来处理 scss 样式;
  • rollup-plugin-esbuild 以及 esbuild , 负责发布时的压缩/混淆。

为了不打乱 package.json 文件中依赖项的顺序, 先编辑 package.json 文件, 讲下面的内容添加到 devDependencies 的尾部

{
  "devDependencies": {
    "@angular-devkit/build-angular": "~12.2.10",
    "@angular/cli": "~12.2.10",
    "@angular/compiler-cli": "~12.2.0",
    "@types/node": "^12.11.1",
    "ng-packagr": "^12.1.1",
    "typescript": "~4.3.5",
+    "rollup": "^2.58.0",
+    "@rollup/plugin-alias": "^3.1.5",
+    "@rollup/plugin-commonjs": "^21.0.0",
+    "@rollup/plugin-node-resolve": "^13.0.5",
+    "@rollup/plugin-replace": "^3.0.0",
+    "@rollup/plugin-typescript": "^8.2.5",
+    "rollup-plugin-scss": "^3.0.0",
+    "rollup-plugin-esbuild": "^4.5.0",
+    "sass": "^1.43.2",
+    "esbuild": "^0.13.6"
  }
}

保存 package.json 文件, 再在终端中执行 npm -i 并等待完成。

编写 Rollup 配置文件

接下来编写一个 rollup 的配置文件 rollup.config.js

import alias from '@rollup/plugin-alias';
import commonjs from '@rollup/plugin-commonjs';
import { nodeResolve } from '@rollup/plugin-node-resolve';
import scss from 'rollup-plugin-scss';
import esbuild from 'rollup-plugin-esbuild';

import path from 'path';

// `npm run build` -> `production` is true
// `npm run dev` -> `production` is false
const production = !process.env.ROLLUP_WATCH;

/** @type {import('rollup').RollupOptions} */
const rollupOptions = {
    input: [
        './out-tsc/app/main.js',
        './out-tsc/app/polyfills.js'
    ],
    output: {
        dir: path.resolve(__dirname, 'dist'),
        format: 'esm',
        // manualChunks: (id) => {},
        sourcemap: !production,
    },
    watch: { clearScreen: false },
    treeshake: production,
    plugins: [
        nodeResolve({}),
        esbuild({ legalComments: 'none', minify: production })
    ]
};

export default rollupOptions;

有了这个配置文件, 就可以使用 rollup 进行打包了, rollup 打包命令为

npx rollup -c rollup.config.js

执行完毕之后, 输出结果为 dist/main.jsdist/polyfills.js

使用 Rollup 的优缺点分析

先说一下使用 Rollup 进行打包的缺点, 主要有:

  • 配置比较多,需要额外编写 rollup 的配置文件,没有 angular-cli 来的简单直接;
  • 依赖 angular-cli 的 ngc 命令进行编译;
  • Rollup 暂时不支持对 node_modules 目录下的类库进行 treeshake , 输出的结果会稍微大一些;

但是, Rollup 的优势也是很明显的:

  • 虽然配置比较多, 但是胜在可以灵活, 输出结果可控,比如可以将整个 Angular 输出为单个的 js 文件, 在和其它应用集成时会有很大的优势;
  • 输出结果纯净,不像 webpack 那样夹带私货 (webpack runtime) ;

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK