Is there any way of building my svelte or react application in a way, that the three.js module (which I usually import using npm) will be declared as a script tag which will call the module from a CDN? I would like to keep the advantages of a framework but also be able to reduce my final bundle size, since most of my bundle contains three code.
Thank you for your wisdom
Advertisement
Answer
There are two ways to go about your goal of reducing bundle size:
- Importing from a CDN (your suggestion)
- Code-splitting
Importing from a CDN
To keep semantics of ESModules, you may simply replace your current three.js
imports with a URL from an npm CDN, like unpkg
:
Pros | Cons |
---|---|
No extra configuration needed | Slower to load, as browser needs to spin up new connections to access third-party CDN |
Asynchronously
<script> // App.svelte import('https://unpkg.com/three@0.133.1/build/three.min.js').then(({ default: THREE }) => { // your code here }); </script>
Synchronously
Note: Importing like this blocks the rest of your script from loading while
three.js
is downloading, which defeats the purpose of the whole shebang. It’s just here for completeness
<script> // App.svelte import { default as THREE } from 'https://unpkg.com/three@0.133.1/build/three.min.js'; // your code here </script>
Code-splitting
This method takes advantage of the fact that you’re already using a bundler (probably rollup
, vite
, or webpack
). This answer will focus on rollup
as it’s the default used in svelte
‘s examples.
Pros | Cons |
---|---|
Faster to load, as browser can use existing connections to access first-party resources | More complicated to get set up |
Asynchronously
In your rollup.config.js
file, ensure output.format
is set to 'esm'
& output.dir
is set instead of output.file
// rollup.config.js import svelte from 'rollup-plugin-svelte'; import resolve from '@rollup/plugin-node-resolve'; import commonjs from '@rollup/plugin-commonjs'; import postcss from 'rollup-plugin-postcss'; const production = !process.env.ROLLUP_WATCH; export default { input: 'src/index.js', output: { sourcemap: !production, format: 'esm', name: 'app', dir: 'public', }, plugins: { // your plugins svelte({ compilerOptions: { dev: !production, }, }), postcss({ extract: 'bundle.css', }), resolve({ browser: true, dedupe: ['svelte'], }), commonjs(), } }
<script> // App.svelte import('three').then(({ default: THREE }) => { // your code here }); </script>
Note: There is no synchronous way due to how code-splitting is evaluated at compile time. Plus it doesn’t make much sense to do it like that anyways.