You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在NX工作区的Angular Webpack项目中集成Workbox的构建优化问询

问题

我正尝试将项目中的ServiceWorker从@angular/service-worker切换为Workbox,但相关文档缺少优质示例。我了解Workbox是框架无关工具,但当前构建流程较为繁琐。请问是否有更精简的实现方式?或者我当前的做法是否符合最佳实践?

我的项目结构如下:

apps
⨽ myApp
  ⊦ sw.ts                  ← My Workbox SW template
  ⊦ tsconfig.workbox.json  ← Only needed because of my extra webpack build step
  ⊦ webpack.config.js      ← Config of the extra build step
  ⊦ workbox-build.js       ← Config for the workbox-cli when injecting
  ⊦ project.json           ← NX version of the angular cli config
dist
⨽ apps
  ⨽ myApp

sw.ts

import { clientsClaim, skipWaiting } from 'workbox-core';
import { cleanupOutdatedCaches, precacheAndRoute } from 'workbox-precaching';

declare const self: ServiceWorkerGlobalScope;

skipWaiting();
clientsClaim();
cleanupOutdatedCaches();

precacheAndRoute(self.__WB_MANIFEST); // Will be filled in build time

tsconfig.workbox.json:

{
  "compilerOptions": {
    "typeRoots": ["./typings"],
    "module": "esnext",
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "es2015",
    "lib": ["esnext", "webworker"]
  },
  "files": ["./sw.ts"]
}

webpack.config.js:

const path = require('path');

module.exports = {
  mode: 'production',
  output: {
    path: path.resolve(__dirname, '../../dist/apps/myApp'),
    filename: 'sw.js',
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        options: { configFile: 'tsconfig.workbox.json' },
      },
    ],
  },
  resolve: { extensions: ['.js', '.ts'] },
};

workbox-build.js:

const { injectManifest } = require('workbox-build');

const workboxConfig = {
  globDirectory: 'dist/apps/myApp',
  globPatterns: ['**/*.{css,eot,html,ico,jpg,js,json,png,svg,ttf,txt,webmanifest,woff,woff2,webm,xml}'],
  globFollow: true, // follow symlinks
  globStrict: true, // fail on error
  globIgnores: [
    `**/*-es5.js*`,
    'sw.js',
  ],
  // Allows to avoid using cache busting for Angular files because Angular already takes care of that!
  dontCacheBustURLsMatching: new RegExp('.+.[a-f0-9]{20}..+'),
  maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, // 10MB
  swSrc: 'dist/apps/myApp/sw.js',
  swDest: 'dist/apps/myApp/sw.js',
};

// Calling the method and output the result
injectManifest(workboxConfig).then(({ count, size }) => {
  console.log(`Generated ${workboxConfig.swDest},
  which will precache ${count} files, ${size} bytes.`);
});

我的package.json中有如下脚本:

"build:wb": "webpack ./apps/myApp/sw.ts --config ./apps/myApp/webpack.config.js && node ./apps/myApp/workbox-build.js"

该脚本会执行两个任务:1)编译sw.ts;2)将静态资源作为预缓存注入编译后的sw.js。但我认为这种方案较为杂乱。

Angular本身已使用Webpack构建,能否将该构建流程集成到project.json中,使用自定义Webpack配置在Angular Webpack构建完成后自动执行?是否必须在Angular构建完成后手动触发这一额外的构建步骤?

我设想的理想方案是:在project.json中引用自定义Webpack配置,使其作为Angular构建流程的最后一步执行。该Webpack配置会先编译sw.ts,然后收集Angular构建生成的静态文件,将这些文件的预缓存注入编译后的sw.ts,并将结果输出到dist目录中,与Angular编译产物放在一起。这样可以省去额外的tsconfig文件和单独的构建脚本,让整个构建流程更易理解。


优化方案

一、精简流程,集成到NX/Angular构建链

你当前的做法逻辑通顺,但确实可以进一步精简——核心是把Workbox的编译、预缓存注入整合到Angular的构建流程中,删掉冗余的独立配置和脚本,让整个流程自动化。

1. 移除冗余文件

直接删除tsconfig.workbox.json、独立的webpack.config.js和workbox-build.js,将所有逻辑整合到一个自定义Webpack配置中。

2. 创建集成式Webpack配置(webpack.workbox.js)

在apps/myApp下新建该文件,同时处理TS编译和Workbox预缓存注入:

const path = require('path');
const { injectManifest } = require('workbox-build');

module.exports = {
  mode: 'production',
  entry: './sw.ts',
  output: {
    path: path.resolve(__dirname, '../../dist/apps/myApp'),
    filename: 'sw.js',
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: [
          {
            loader: 'ts-loader',
            options: {
              compilerOptions: {
                typeRoots: ['./typings'],
                module: 'esnext',
                moduleResolution: 'node',
                importHelpers: true,
                target: 'es2015',
                lib: ['esnext', 'webworker']
              }
            }
          }
        ]
      }
    ]
  },
  resolve: {
    extensions: ['.js', '.ts']
  },
  plugins: [
    {
      apply: (compiler) => {
        // Webpack编译完成后自动执行Workbox预缓存注入
        compiler.hooks.afterEmit.tapAsync('WorkboxInject', (compilation, callback) => {
          injectManifest({
            globDirectory: path.resolve(__dirname, '../../dist/apps/myApp'),
            globPatterns: ['**/*.{css,eot,html,ico,jpg,js,json,png,svg,ttf,txt,webmanifest,woff,woff2,webm,xml}'],
            globFollow: true,
            globStrict: true,
            globIgnores: [
              `**/*-es5.js*`,
              'sw.js',
            ],
            dontCacheBustURLsMatching: new RegExp('.+.[a-f0-9]{20}..+'),
            maximumFileSizeToCacheInBytes: 10 * 1024 * 1024,
            swSrc: path.resolve(__dirname, '../../dist/apps/myApp/sw.js'),
            swDest: path.resolve(__dirname, '../../dist/apps/myApp/sw.js'),
          }).then(({ count, size }) => {
            console.log(`Workbox: 预缓存 ${count} 个文件,总大小 ${size} 字节`);
            callback();
          }).catch(err => {
            console.error('Workbox注入失败:', err);
            callback(err);
          });
        });
      }
    }
  ]
};

3. 修改project.json,绑定构建流程

在project.json的targets中新增build-sw目标,并让主build目标自动依赖它:

{
  "targets": {
    "build": {
      // 保留原有的build配置
      "dependsOn": ["build-sw"]
    },
    "build-sw": {
      "executor": "@nrwl/webpack:webpack",
      "options": {
        "webpackConfig": "apps/myApp/webpack.workbox.js",
        "outputPath": "dist/apps/myApp"
      }
    }
  }
}

4. 调整脚本(可选)

如果需要单独触发SW构建,可修改package.json脚本:

"build:sw": "nx run myApp:build-sw"

二、关键优化说明

  • 合并两步操作:通过Webpack的afterEmit钩子,在SW编译完成后立即执行预缓存注入,无需分两次调用脚本;
  • 复用TS配置:直接在ts-loader中指定WebWorker所需的编译参数,省去独立的tsconfig.workbox.json;
  • 自动化流程:通过NX的dependsOn让主构建自动触发SW构建,无需手动执行额外命令,流程更连贯。

三、关于最佳实践

你最初的手动集成是Workbox的标准用法,本身没有问题,但集成到框架构建链中是更优的实践:

  • 减少手动操作,降低出错概率;
  • 构建逻辑更集中,团队成员无需额外学习独立脚本;
  • 便于后续扩展(比如添加路由缓存、离线页面等功能)。

内容的提问来源于stack exchange,提问作者Øystein Amundsen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 01:55:53