这是一个复杂的话题,也是同样开放式的问题!为了回答这个问题,我将做一些假设:
- 节省 AWS 成本意味着减少捆绑包大小,从而节省传出带宽成本。
- 正在构建的应用程序是 100% SPA 即完全客户端。服务器端优化很快就会变得非常复杂。
开箱即用,Webpack 会将所有内容捆绑到一个大文件/包中。它包含您自己的代码以及来自第三方库的代码。 这里的基本思想是第三方代码很少更改,而我们自己的代码经常更改。
因此,我们可以使用 Webpack 将我们的代码拆分为两个不同的夹头,使用 SplitChunksPlugin。一个用于我们自己的代码,另一个用于第三方代码,即来自node_modules 文件夹的代码;让我们称之为供应商捆绑。现在,只要您的 node_modules 文件夹保持不变,即您的锁定文件 - package-lock.json 文件保持不变,它就会始终为第三方代码生成具有完全相同内容的相同包。
接下来的想法是您可以简单地获取此供应商捆绑包并将其上传到 CDN,然后通过 CDN 使用。 CDN 和浏览器会发挥它们的缓存魔法,用户几乎不需要每次都下载这个文件。 CDN 将使用ETag 和/或cache-control 标头来实现这一点,浏览器将使用它。
然而,实际情况有所不同。当你有太多依赖或者使用 dependabot 更新依赖时,你会经常更新你的锁文件。这意味着在每次构建时都会生成一个新的供应商捆绑包,即使存在单个字节的差异。 Webpack 生成的 hash id 会有所不同。而在其他情况下,您导入依赖项的方式也可能会更改生成的包内容,从而导致不同的包。
因此,在架构上,我们通过使用 CDN 来更好地捆绑供应商。第一步是区分稳定的第三方模块和经常更新的第三方模块。例如,考虑react、react-dom 和rxjs 等。这些不经常更新。对于这些库,请使用 cloudflare、cdnjs 或 unpkg 等第三方 CDN。将这些库添加为基于 CDN 的 UMD 包。
为此,您需要将这些依赖项添加到您的 index.html 文件中,该文件通常使用 html-webpack-plugin 生成。
<!-- index.html -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
现在,只需告诉 Webpack 不要捆绑您已经通过 CDN script 提供的这些依赖项。使用 Webpack externals 来做到这一点:
// webpack.config.js
module.exports = {
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
},
};
有了这个配置,Webpack 不仅会从包中排除 React,还会加快你的打包速度。无论你从 React 库中导入什么东西,Webpack 都会将其替换为全局对象 React。
然后您可以将此模型扩展到您正在使用的所有稳定库。 使用这种方式的另一个重要优势是,您的用户可能已经访问过其他网站,这些网站会使用相同的 CDN 在他们的浏览器中缓存此特定文件。
要自动化您的工作流程,您可以自定义 Webpack 或任何捆绑程序脚本,以通过读取您的依赖项的 packge.json 文件然后生成 <script> 标记来注入具有精确版本的这些脚本。这意味着您的依赖项版本仍然有单一的事实来源。您可以阅读 CDN documentation 以了解它们如何允许您为依赖项构建 CDN URL。