# svelte-loader is the webpack path into Svelte, and the README says so

> svelte-loader is a webpack loader that compiles Svelte components, with the configuration detail that webpack needs: a resolve block to avoid bundling two copies of the Svelte runtime, a CSS extraction path, TypeScript handling and the fullySpecified escape hatch for webpack 5. Its own README opens by suggesting SvelteKit or Vite instead, which tells you who should be reading it.

**sveltejs/svelte-loader** — Webpack loader for svelte components. 

- Repository: https://github.com/sveltejs/svelte-loader
- Stars: 604 · Forks: 72
- Language: JavaScript
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/sveltejs-svelte-loader

## The first line of the README is a recommendation to use something else

The README opens, before the title and before the badges, with a note for anyone who has not yet decided on a bundler: it suggests using SvelteKit, or Vite with vite-plugin-svelte.

That is unusual, and it is the most useful thing in the file. A loader that tells you to pick a different tool is not trying to grow; it is telling you where its own use case ends.

What svelte-loader is, on the other hand, is a webpack loader for Svelte. A loader is a webpack mechanism where a file in your source tree is transformed on the way into the bundle, and this one takes a .svelte file and turns it into JavaScript the bundler can handle.

The audience that remains is a team with an existing webpack build who needs Svelte components inside it. That is a real situation: an established application, a design system written in Svelte, a company standard on webpack, or a project that cannot move its build tool yet. For those cases the loader is the tool, and the rest of the README is a careful guide to configuring it correctly.

The repository itself is small and conventional, with index.js and a lib directory holding the implementation, a test directory, an .eslintrc, a CHANGELOG.md, a LICENSE.md file and a Travis build badge.

## Installing and the resolve block you cannot skip

The install is one command, and the package names matter because both the framework and the loader are needed:

```bash
npm install --save svelte svelte-loader
```

The configuration lives in your webpack.config.js, and the first part of it is the resolve block:

```javascript
  resolve: {
    // see below for an explanation
    alias: {
      svelte: path.resolve('node_modules', 'svelte/src/runtime') // Svelte 3: path.resolve('node_modules', 'svelte')
    },
    extensions: ['.mjs', '.js', '.svelte'],
    mainFields: ['svelte', 'browser', '...'],
    conditionNames: ['svelte', 'browser', '...'],
  },
```

Three of those four lines exist to solve the same problem, which is why the README explains each one separately.

The alias is used to make sure that only one copy of the Svelte runtime is bundled in the app, even if you are npm link-ing in dependencies with their own copy of the svelte package. The README is blunt about the consequence of getting it wrong: having multiple copies of the internal scheduler in an app is inefficient and can also cause various problems.

That is the failure mode to fear. A duplicated Svelte runtime does not produce a clear error, it produces an application that misbehaves, and the cause is a line in your resolve block.

The mainFields option determines which fields in package.json are used to resolve identifiers, and the conditionNames option does the same for the exports field. Both are needed so that your app can use the original component source code rather than consuming the already-compiled version, which the README notes is less efficient.

There is also an example project, the sveltejs/template-webpack repository, which is worth reading before writing the config from scratch.

## The module rules for Svelte 5, TypeScript and webpack 5

The rules array carries the version-specific parts, and the comments in the README are the documentation.

Two loader entries are only needed if you use Svelte 5+ with TypeScript. The first matches .svelte.ts files and chains the Svelte loader with ts-loader in transpileOnly mode. The second is the config for other .ts files, and its regex makes sure the .svelte.ts files are not processed twice, which the negative lookbehind in the pattern handles.

The TypeScript entries also carry a warning: make sure your tsconfig.json includes "useDefineForClassFields": true, or "target" is at least "ES2022", in order to not downlevel class syntax. That is a Svelte 5 requirement leaking into your TypeScript configuration, and it is the kind of detail that produces a runtime error rather than a compile error if it is missed.

The main Svelte rule has three commented variants, and which one you use depends on your version. For Svelte 5+ the test is /\.(svelte|svelte\.js)$/. For Svelte 3 or 4 it is /\.svelte$/. And if you write Svelte in HTML, which the README says is not recommended since Svelte 3, the test becomes /\.(html|svelte)$/.

The last rule is the one that catches people out on webpack 5. It matches node_modules/svelte/*.mjs and sets resolve.fullySpecified to false, and the comment says it is required to prevent errors from Svelte on Webpack 5+, and to omit it on Webpack 4.

The alternatives in the same list are the modern ones. If you are starting a new project, SvelteKit or Vite with vite-plugin-svelte removes all of this.

## Getting the CSS out of the JavaScript bundle

By default, if your Svelte components contain style tags, the compiler adds JavaScript that injects those styles into the page when the component is rendered. The README lists why that is not ideal: it adds weight to your JavaScript, it prevents styles from being fetched in parallel with your code, and it can even cause CSP violations.

The fix is the emitCss option, which causes a virtual CSS file to be emitted for each Svelte component, and the resulting file is then imported by the component, following the standard webpack compilation flow. You add MiniCssExtractPlugin to the mix to output the CSS to a separate file:

```javascript
      {
        test: /\.(svelte|svelte\.js)$/,
        use: {
          loader: 'svelte-loader',
          options: {
            emitCss: true,
          },
        },
      },
```

Two details are worth copying exactly. The css-loader entry sets url: false, with a comment saying it is necessary if you use url('/path/to/some/asset.png|jpg|gif'). And the plugin is constructed with a filename, new MiniCssExtractPlugin('styles.css'), which you change to '[name].css' if you have multiple entrypoints and want one CSS file per entrypoint.

There is a warning that will save you a debugging session. In production, if you have set sideEffects: false in your package.json, MiniCssExtractPlugin has a tendency to drop CSS, regardless of whether it is included in your Svelte components. The sideEffects field is a tree shaking hint, and this is the case where it lies.

And if you handle styles some other way and only want to stop the CSS being added to the JavaScript bundle, there is a smaller option that turns the compiler's CSS handling off, through the compilerOptions key with css set to false.

## Source maps, compiler options and the preprocessor path

JavaScript source maps are enabled by default in this loader, and all you have to do is use an appropriate webpack devtool. For CSS source maps you need emitCss and the sourceMap option on css-loader, which creates an additional styles.css.map file.

The compiler options mechanism is the general escape hatch. You can specify additional arbitrary compilation options with the compilerOptions config key, and they are passed directly to the underlying Svelte compiler:

```js
use: {
  loader: 'svelte-loader',
  options: {
    compilerOptions: {
      // additional compiler options here
      generate: 'ssr', // for example, SSR can be enabled here
    }
  }
},
```

Because the options go straight through to the compiler, this is where server side rendering is switched on, and where anything else the Svelte compiler understands can be set without the loader needing to know about it.

The last documented section is about preprocessors such as TypeScript, and it points at svelte-preprocess. The README is truncated at that point in the copy available here, so the exact configuration for a preprocessor is not specified in what is quoted, and the package reference is cut off mid-word.

That truncation is worth noting for a reader, because the preprocessor path is the part that most often needs adjusting, and it is exactly the part that is cut off. The rest of the file is complete enough to configure the loader, but for a project using TypeScript inside components, the preprocess section is where you will want the full text.

The package metadata also carries the version constraints. The peer dependency range is svelte ^3.0.0 || ^4.0.0-next.0 || ^5.0.0-next.1, while the development dependency is svelte ^4.0.0, so the loader is developed and tested against Svelte 4 with early prereleases of 3 and 5 allowed for consumers.

## Maintenance, dependencies and how to decide

The last push was on 2026-04-02, and the repository is not archived. There are no GitHub releases, so the published version is what the npm registry carries, and the manifest version is 3.2.4.

The dependency surface is small and old-fashioned in a way that tells you something. The runtime dependencies are loader-utils, svelte-dev-helper and svelte-hmr, the last of which is the hot module replacement helper. The build dependency set is mocha with chai, sinon and sinon-chai, and eslint with the mocha plugin. The scripts are the classic all, test, lint and prepublishOnly set, with the test script running mocha with --harmony, --full-trace and --check-leaks.

The licence is MIT, which for a build-time loader is about as uncomplicated as it gets, and the published files list is just lib and index.js.

Putting that together with the README's opening recommendation, the decision is fairly clear. If you are building something new in Svelte, the maintainers of Svelte itself point you at SvelteKit or Vite, and the loader's own configuration guide, the alias for the runtime, the fullySpecified rule, the sideEffects warning and the TypeScript tsconfig requirement, are all signs of a tool that is maintained for people who are not starting fresh.

If you already have a webpack build, this guide is the answer to the specific failure modes you will hit, and the example project is the fastest way to a working configuration. Either way, copy the resolve block and the rules from the README rather than from memory, because every one of those lines exists to prevent a bug that does not announce itself.

## Conclusion

svelte-loader fits a team already committed to webpack who needs to render Svelte components inside an existing build, and the configuration it documents is the real value, since the resolve and rules blocks are the part people get wrong. It is the wrong choice for a new Svelte project, and the README says so in its first line by pointing you at SvelteKit or Vite with vite-plugin-svelte. Verify first that the peer dependency range covers the Svelte version you run, because the range allows 3.x and a 4.x prerelease and a 5.x prerelease while the development dependency is still Svelte 4, then copy the resolve block from the example rather than from memory, because a duplicated Svelte runtime fails in ways that look like application bugs.

## FAQ

### Should I use svelte-loader for a new Svelte project?

The README's first line suggests SvelteKit, or Vite with vite-plugin-svelte, for anyone who has not yet decided on a bundler. svelte-loader is for teams already committed to webpack who need to compile Svelte components inside an existing build.

### How do I install svelte-loader?

With npm install --save svelte svelte-loader, and then configure it in your webpack.config.js. The README links an example project, sveltejs/template-webpack, that shows a complete configuration.

### Why does the svelte-loader webpack config need a resolve.alias for svelte?

The alias makes sure only one copy of the Svelte runtime is bundled, even when dependencies are npm link-ed with their own copy of the svelte package. The README notes that multiple copies of the internal scheduler are inefficient and can cause various problems.

### How do I extract the CSS from a Svelte component in webpack?

Set the emitCss option on svelte-loader so a virtual CSS file is emitted per component, and add MiniCssExtractPlugin with css-loader to write it out. The README warns that in production, setting sideEffects: false in package.json makes MiniCssExtractPlugin drop CSS.

## Sources

- [Issues](https://github.com/sveltejs/svelte-loader/issues)
- [License: MIT](https://github.com/sveltejs/svelte-loader/blob/master/LICENSE)
- [README](https://github.com/sveltejs/svelte-loader/blob/master/README.md)
- [sveltejs/svelte-loader on GitHub](https://github.com/sveltejs/svelte-loader)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/sveltejs-svelte-loader
