Add a Svelte Project

The code for this example is available on GitHub:

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 acme --preset=ts-standalone --nx-cloud=true

Add @nx/vite, svelte, and other dependencies to your workspace

Keep Nx Package Versions In Sync

Make 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

Nx 15 and lower use @nrwl/ instead of @nx/

Create the application

Create your index.html at the root with the following:

1<!DOCTYPE html> 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 src/index.ts and change it to src/main.ts and add the following content:

1import App from './App.svelte'; 2 3const app = new App({ 4 target: document.getElementById('app'), 5}); 6 7export default app; 8

Create a new file src/App.svelte and add the following content:

src/App.svelte
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

Since we have a .svelte file, we'll need to tell typescript how to handle it. Create a new file src/svelte-shims.d.ts and add the following content:

src/svelte-shims.d.ts
1declare module '*.svelte' { 2 import type { ComponentType } from 'svelte'; 3 const component: ComponentType; 4 export default component; 5} 6

Alternatively, you could also extend the tsconfig.json file to use tsconfig/svelte.

tsconfig.json
1{ 2 "extends": "@tsconfig/svelte/tsconfig.json" 3 //... other configs 4} 5

See more here: Svelte TypeScript

Configure Nx to build and serve the application

Navigate to vite.config.ts add svelte to your plugins.

1// Add this to your imports 2import { svelte } from '@sveltejs/vite-plugin-svelte'; 3 4export default defineConfig({ 5 plugins: [ 6 //... other plugins 7 svelte(), // Add this line 8 ], 9 //... 10 server: { 11 port: 4200, 12 host: 'localhost', 13 }, 14}); 15

Change your tsconfig.lib.json to tsconfig.app.json. It should look like this:

/tsconfig.app.json
1{ 2 "extends": "./tsconfig.json", 3 "compilerOptions": { 4 "outDir": "./dist/out-tsc", 5 "declaration": true, 6 "types": ["node"] 7 }, 8 "include": ["src/**/*.ts", "src/**/*.svelte"], 9 "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 10} 11

Navigate to project.json and update it with the following content:

/project.json
1{ 2 "targets": { 3 "build": { 4 "executor": "@nx/vite:build", 5 "outputs": ["{options.outputPath}"], 6 "defaultConfiguration": "production", 7 "options": { 8 "outputPath": "dist/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
Nx 15 and lower use @nrwl/ instead of @nx/

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:

/package.json
1{ 2 "type": "module" 3} 4
Why use the type: module?

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/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.

Directory Flag Behavior Changes

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 as-provided vs. derived documentation for more details.

โฏ

nx generate @nx/js:library --name=Counter --directory=libs/counter --unitTestRunner=vitest --bundler=vite --importPath=@acme/counter

Nx 15 and lower use @nrwl/ instead of @nx/

Create the Counter component at libs/counter/src/lib/Counter.svelte and copy the contents of your 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
Remember the default keyword

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 vite.config.ts 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 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/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.