Add a Svelte Project
The code for this example is available on GitHub:
Example repository/nrwl/nx-recipes/tree/main/svelte
Supported Features
Because we are not using a Nx plugin for Svelte, there are a few items we'll have to configure manually. We'll have to configure our own build system. There are no pre-created Svelte-specific code generators. And we'll have to take care of updating any framework dependencies as needed.
✅ Run Tasks ✅ Cache Task Results ✅ Share Your Cache ✅ Explore the Graph ✅ Distribute Task Execution ✅ Integrate with Editors ✅ Automate Updating Nx ✅ Enforce Module Boundaries 🚫 Use Task Executors 🚫 Use Code Generators 🚫 Automate Updating Framework Dependencies
Setup workspace
Create a new Nx workspace
❯
npx create-nx-workspace@latest workspace --preset=react-monorepo --style=css --bundler=vite --nx-cloud=true --appName=acme
Add @nx/vite, svelte, and other dependencies to your workspace
Keep Nx Package Versions In SyncMake sure to install the @nx/vite
and @nx/js
versions that matches the version of nx
in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can fix Nx version mismatches with this recipe.
❯
npm install --save-dev @nx/vite @nx/js vitest vite svelte svelte-check @sveltejs/vite-plugin-svelte
Create the application
Before we start to create our application, let's remove the React application that was created for us.
❯
rm -rf apps/acme/src/app/*
Update your apps/acme/src/index.html
to the following:
1
2<html lang="en">
3 <head>
4 <meta charset="UTF-8" />
5 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6 <title>Acme</title>
7 </head>
8 <body>
9 <div id="app"></div>
10 <script type="module" src="./src/main.ts"></script>
11 </body>
12</html>
13
Navigate to apps/acme/src/main.tsx
and change it to apps/acme/src/main.ts
and add the following content:
1import App from './app/App.svelte';
2
3const app = new App({
4 target: document.getElementById('app'),
5});
6
7export default app;
8
Create a new file apps/acme/src/app/App.svelte
and add the following content:
1<script lang="ts">
2 let count: number = 0
3 const increment = () => {
4 count += 1
5 }
6 </script>
7
8 <button on:click={increment}>
9 count is {count}
10 </button>
11
12
Configure Nx to build and serve the application
Navigate to vite.config.ts
update the file name to vite.config.mts
and add the following content:
1// Add this to your imports
2import { svelte } from '@sveltejs/vite-plugin-svelte';
3
4export default defineConfig({
5 plugins: [
6 //...
7 svelte(),
8 ],
9
10 server: {
11 port: 4200,
12 host: 'localhost',
13 },
14});
15
We change vite.config.ts
to vite.config.mts
because '@sveltejs/vite-plugin-svelte'
is an ESM only package. As a result, we need to use the .mts
extension to tell Nx to use the ESM loader. See more here: ESM Package
Update your tsconfig.app.json
with the following content:
1{
2 "extends": "./tsconfig.json",
3 "compilerOptions": {
4 "moduleResolution": "node",
5 "target": "esnext",
6 "ignoreDeprecations": "5.0",
7 "isolatedModules": true,
8 "sourceMap": true,
9 "types": ["svelte", "node", "vite/client"],
10 "strict": false,
11 "esModuleInterop": true,
12 "skipLibCheck": true,
13 "forceConsistentCasingInFileNames": true,
14 "checkJs": true
15 },
16 "include": [
17 "src/**/*.d.ts",
18 "src/**/*.ts",
19 "src/**/*.js",
20 "src/**/*.svelte",
21 "vite.config.mts"
22 ],
23 "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
24}
25
Navigate to project.json
and update it with the following content:
1{
2 "targets": {
3 "build": {
4 "executor": "@nx/vite:build",
5 "outputs": ["{options.outputPath}"],
6 "defaultConfiguration": "production",
7 "options": {
8 "outputPath": "dist/apps/acme"
9 },
10 "configurations": {
11 "development": {
12 "mode": "development"
13 },
14 "production": {
15 "mode": "production"
16 }
17 }
18 },
19 "serve": {
20 "executor": "@nx/vite:dev-server",
21 "defaultConfiguration": "development",
22 "options": {
23 "buildTarget": "acme:build"
24 },
25 "configurations": {
26 "development": {
27 "buildTarget": "acme:build:development",
28 "hmr": true
29 },
30 "production": {
31 "buildTarget": "acme:build:production",
32 "hmr": false
33 }
34 }
35 }
36 }
37}
38
We also need to add a svelte.config.js
file to the project root with the following content:
1import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
2
3export default {
4 // Consult https://svelte.dev/docs#compile-time-svelte-preprocess
5 // for more information about preprocessors
6 preprocess: vitePreprocess(),
7};
8
Update your package.json
to include:
1{
2 "type": "module"
3}
4
We need to add "type": "module"
to our package.json
file because we are using ESM only packages. See more here: ESM Package
Test it out
Build the application
❯
nx build acme
Your build artifacts should be in dist/apps/acme
Serve the application
❯
nx serve acme
Navigate to http://localhost:4200
and you should see your application.
Create a library
Instead of having our Counter directly defined in App.svelte
file, let's create a library that we can import into our application.
The command below uses the as-provided
directory flag behavior, which is the default in Nx 16.8.0. If you're on an earlier version of Nx or using the derived
option, omit the --directory
flag. See the workspace layout documentation for more details.
❯
nx generate @nx/js:library --name=Counter --directory=libs/counter --unitTestRunner=vitest --bundler=vite --importPath=@acme/counter
Create the Counter component at libs/counter/src/lib/Counter.svelte
and copy the contents of your apps/acme/src/App.svelte
file into it.
Update your libs/counter/src/lib/index.ts
to export your Counter component.
1export { default as Counter } from './Counter.svelte';
2
The default
is import here as due to the aliasing we'll be doing later, we'll need to import the Counter component as import { Counter } from '@acme/counter'
.
Update your project's /apps/acme/vite.config.mts
to include the following:
1export default defineConfig({
2 //... other config
3 resolve: {
4 alias: {
5 '@acme/counter': fileURLToPath(
6 new URL('/libs/counter/src/index.ts', import.meta.url)
7 ),
8 },
9 },
10});
11
This allows the runtime to resolve the @acme/counter
import to the correct location.
Finally update your apps/acme/src/App.svelte
to use the counter component.
1<script lang="ts">
2 import { Counter } from '@acme/counter';
3</script>
4
5<Counter />
6
Now we can build and serve our application again.
❯
nx build acme
To generate the build artifact at dist/apps/acme
.
❯
nx serve acme
To serve the application at http://localhost:4200
.
More Documentation
A larger example including libraries, test and more is available at Nx Svelte Example on GitHub.