Reputation: 13
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
Upvotes: 1
Views: 1238
Reputation: 375
There are two ways to go about your goal of reducing bundle size:
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/[email protected]/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/[email protected]/build/three.min.js';
// your code here
</script>
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.
Upvotes: 0
Reputation: 1877
Yes, you can do the following:
In your "index.html" file, you can import the js file from a CDN as follow:
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
Then, in the file where you want to use it, which could be a React component for instance, you can do the following:
const THREE = window.THREE;
Which would replace your import statement, which would have been import * as THREE from "three";
or import THREE from "three";
Upvotes: 0