Skip to content

Commit

Permalink
Make it work with Webpack 5, use webpack-virtual-modules as a dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
non25 committed Jan 11, 2021
1 parent d4e2c20 commit 243c69f
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 202 deletions.
43 changes: 32 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ Configure inside your `webpack.config.js`:
test: /\.(html|svelte)$/,
exclude: /node_modules/,
use: 'svelte-loader'
},
{
// required to prevent errors from Svelte on Webpack 5+
test: /svelte\/.*\.mjs$/,
resolve: {
fullySpecified: false
}
}
...
]
Expand All @@ -54,9 +61,13 @@ Webpack's [`resolve.mainFields`](https://webpack.js.org/configuration/resolve/#r

If your Svelte components contain `<style>` tags, by default the compiler will add JavaScript that injects those styles into the page when the component is rendered. That's not ideal, because it adds weight to your JavaScript, prevents styles from being fetched in parallel with your code, and can even cause CSP violations.

A better option is to extract the CSS into a separate file. Using the `emitCss` option as shown below would cause a virtual CSS file to be emitted for each Svelte component. The resulting file is then imported by the component, thus following the standard Webpack compilation flow. Add [ExtractTextPlugin](https://github.com/webpack-contrib/extract-text-webpack-plugin) to the mix to output the css to a separate file.
A better option is to extract the CSS into a separate file. Using the `emitCss` option as shown below would cause a virtual CSS file to be emitted for each Svelte component. The resulting file is then imported by the component, thus following the standard Webpack compilation flow. Add [MiniCssExtractPlugin](https://webpack.js.org/plugins/mini-css-extract-plugin/) to the mix to output the css to a separate file.

Make sure to add SveltePlugin like shown below, which allows emitting virtual CSS files. It is a wrapper around webpack-virtual-modules, connected to the svelte-loader.

```javascript
const SveltePlugin = require('svelte-loader').plugin;
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
...
module: {
rules: [
Expand All @@ -73,17 +84,20 @@ A better option is to extract the CSS into a separate file. Using the `emitCss`
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader',
}),
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
...
]
},
...
plugins: [
new ExtractTextPlugin('styles.css'),
new MiniCssExtractPlugin({
filename: '[name].css'
}),
new SveltePlugin(),
...
]
...
Expand Down Expand Up @@ -115,19 +129,26 @@ module.exports = {
},
},
},

{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{ loader: 'css-loader', options: { sourceMap: true } }],
}),
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: { sourceMap: true }
}
]
},
...
]
},
...
plugins: [
new ExtractTextPlugin('styles.css'),
new MiniCssExtractPlugin({
filename: '[name].css'
}),
new SveltePlugin(),
...
]
...
Expand Down
44 changes: 34 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const { basename, extname, relative } = require('path');
const { getOptions } = require('loader-utils');
const VirtualModules = require('./lib/virtual');
const VirtualModules = require('webpack-virtual-modules');

const hotApi = require.resolve('./lib/hot-api.js');

Expand Down Expand Up @@ -96,13 +96,9 @@ function deprecatePreprocessOptions(options) {
options.preprocess = options.preprocess || preprocessOptions;
}

const virtualModuleInstances = new Map();

module.exports = function(source, map) {
if (this._compiler && !virtualModuleInstances.has(this._compiler)) {
virtualModuleInstances.set(this._compiler, new VirtualModules(this._compiler));
}
let virtualModuleInstances = new WeakMap();

function loader(source, map) {
const virtualModules = virtualModuleInstances.get(this._compiler);

this.cacheable();
Expand Down Expand Up @@ -169,9 +165,26 @@ module.exports = function(source, map) {
css.code += '\n/*# sourceMappingURL=' + css.map.toUrl() + '*/';
js.code = js.code + `\nimport '${posixify(cssFilepath)}';\n`;

if (virtualModules) {
virtualModules.writeModule(cssFilepath, css.code);
if (!virtualModules) {
throw new Error(
`
To be able to use emitCss: true, add
const SveltePlugin = require('svelte-loader').plugin;
to the top of your webpack.config.js and
SveltePlugin to the plugins array like this
plugins: [
...
new SveltePlugin()
]
`.split('\n').map(s => s.slice(5)).join('\n')
);
}

virtualModules.writeModule(cssFilepath, css.code);
}

callback(null, js.code, js.map);
Expand All @@ -180,4 +193,15 @@ module.exports = function(source, map) {
// context when logging to console
callback(new Error(`${err.name}: ${err.toString()}`));
});
};
}

class SveltePlugin extends VirtualModules {
apply(compiler) {
virtualModuleInstances.set(compiler, this);
super.apply(compiler);
}
}

loader.plugin = SveltePlugin;

module.exports = loader;
89 changes: 0 additions & 89 deletions lib/virtual-stats.js

This file was deleted.

89 changes: 0 additions & 89 deletions lib/virtual.js

This file was deleted.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "svelte-loader",
"version": "2.13.6",
"version": "3.0.0",
"author": "Nico Rehwaldt <git_nikku@nixis.de>",
"description": "A webpack loader for svelte",
"license": "MIT",
Expand All @@ -16,7 +16,8 @@
],
"dependencies": {
"loader-utils": "^1.1.0",
"svelte-dev-helper": "^1.1.9"
"svelte-dev-helper": "^1.1.9",
"webpack-virtual-modules": "^0.4.1"
},
"devDependencies": {
"chai": "^4.1.2",
Expand All @@ -25,7 +26,7 @@
"mocha": "^5.2.0",
"sinon": "^6.1.5",
"sinon-chai": "^3.2.0",
"svelte": "^3.0.0-beta.5"
"svelte": "^3.0.0"
},
"peerDependencies": {
"svelte": ">1.44.0"
Expand Down

0 comments on commit 243c69f

Please sign in to comment.