在SvelteKit中同时使用外部模块CDN与npm包的更优方案
在SvelteKit中实现客户端CDN加载依赖、服务端复用npm包的简洁方案需求
我在SvelteKit项目里有可前后端复用的通用JS文件,这类文件依赖moment.js(实际项目用date-fns,此处仅作示例)。希望实现:客户端通过CDN加载该依赖模块,服务端则使用npm包,避免把依赖打包进前端产物里。
原实现(存在依赖被打包的问题)
通用JS文件
import moment from 'moment'; export const mylib = () => { return moment().format(); };
Svelte页面代码
<script> import moment from 'moment'; </script> <div> {moment().format()} </div>
这个实现能正常运行,但moment.js会被打包进前端产物,不符合需求。
我尝试的繁琐实现(虽生效但代码冗余、存在问题)
- 在
app.html中引入CDN并添加加载回调:
<script async defer src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js" onload="momentLoad()"></script> <script> window.momentWaits = []; const momentLoad = () => { for(const momentWait of window.momentWaits){ momentWait(); } delete window.momentWaits; }; </script>
- 将moment从
devDependencies移至dependencies:
{ "dependencies": { "moment": "^2.29.4" } }
- 在
vite.config.js中配置外部依赖:
export default defineConfig({ build: { rollupOptions: { external: ['moment'] } }, });
- 修改通用JS文件,区分环境获取moment实例:
let moment = null; if(typeof window == 'undefined') { (async () => import('moment').then((res) => moment = res.default))(); }else { // eslint-disable-next-line no-undef const w = window; if(w.moment){ moment = w.moment; }else{ w.momentWaits.push(() => { moment = w.moment; }); } } export const mylib = () => { if(!moment){ console.log('not yet.'); return; } return moment().format(); };
这里用typeof window == 'undefined'判断环境时构建会报错,改用$app/environment的browser变量可以解决,但这个通用JS文件需要在非Svelte环境运行,所以没采用。
- 修改Svelte页面,在
onMount中处理moment加载逻辑:
<script> import { onMount } from 'svelte'; let moment = null; onMount(async () => { if(window.moment){ moment = window.moment; }else{ window.momentWaits.push(() => { moment = window.moment; }); } }); </script> <div> {#if moment} {moment().format()} {:else} wait... {/if} </div>
这个实现不仅代码冗余,还存在构建报错、CDN加载时机等问题。
需求
希望找到更简洁的实现方式,比如是否有构建时忽略特定错误的配置,或者更合适的事件替代onMount来处理CDN加载逻辑。
内容的提问来源于stack exchange,提问作者enoeht
相关产品推荐
相关产品推荐

