Skip to content

Commit c9db621

Browse files
committed
Make it work with Webpack 5, use webpack-virtual-modules as a dependency
1 parent d4e2c20 commit c9db621

File tree

6 files changed

+70
-215
lines changed

6 files changed

+70
-215
lines changed

README.md

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ Configure inside your `webpack.config.js`:
3333
test: /\.(html|svelte)$/,
3434
exclude: /node_modules/,
3535
use: 'svelte-loader'
36+
},
37+
{
38+
// required to prevent errors from Svelte on Webpack 5+
39+
test: /node_modules\/svelte\/.*\.mjs$/,
40+
resolve: {
41+
fullySpecified: false
42+
}
3643
}
3744
...
3845
]
@@ -54,9 +61,13 @@ Webpack's [`resolve.mainFields`](https://webpack.js.org/configuration/resolve/#r
5461

5562
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.
5663

57-
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.
64+
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.
65+
66+
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.
5867

5968
```javascript
69+
const SveltePlugin = require('svelte-loader').plugin;
70+
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
6071
...
6172
module: {
6273
rules: [
@@ -73,17 +84,20 @@ A better option is to extract the CSS into a separate file. Using the `emitCss`
7384
},
7485
{
7586
test: /\.css$/,
76-
use: ExtractTextPlugin.extract({
77-
fallback: 'style-loader',
78-
use: 'css-loader',
79-
}),
87+
use: [
88+
MiniCssExtractPlugin.loader,
89+
'css-loader'
90+
]
8091
},
8192
...
8293
]
8394
},
8495
...
8596
plugins: [
86-
new ExtractTextPlugin('styles.css'),
97+
new MiniCssExtractPlugin({
98+
filename: '[name].css'
99+
}),
100+
new SveltePlugin(),
87101
...
88102
]
89103
...
@@ -115,19 +129,26 @@ module.exports = {
115129
},
116130
},
117131
},
132+
118133
{
119134
test: /\.css$/,
120-
use: ExtractTextPlugin.extract({
121-
fallback: 'style-loader',
122-
use: [{ loader: 'css-loader', options: { sourceMap: true } }],
123-
}),
135+
use: [
136+
MiniCssExtractPlugin.loader,
137+
{
138+
loader: 'css-loader',
139+
options: { sourceMap: true }
140+
}
141+
]
124142
},
125143
...
126144
]
127145
},
128146
...
129147
plugins: [
130-
new ExtractTextPlugin('styles.css'),
148+
new MiniCssExtractPlugin({
149+
filename: '[name].css'
150+
}),
151+
new SveltePlugin(),
131152
...
132153
]
133154
...

index.js

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const { basename, extname, relative } = require('path');
22
const { getOptions } = require('loader-utils');
3-
const VirtualModules = require('./lib/virtual');
3+
const VirtualModules = require('webpack-virtual-modules');
44

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

@@ -96,13 +96,9 @@ function deprecatePreprocessOptions(options) {
9696
options.preprocess = options.preprocess || preprocessOptions;
9797
}
9898

99-
const virtualModuleInstances = new Map();
100-
101-
module.exports = function(source, map) {
102-
if (this._compiler && !virtualModuleInstances.has(this._compiler)) {
103-
virtualModuleInstances.set(this._compiler, new VirtualModules(this._compiler));
104-
}
99+
let virtualModuleInstances = new WeakMap();
105100

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

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

172-
if (virtualModules) {
173-
virtualModules.writeModule(cssFilepath, css.code);
168+
if (!virtualModules) {
169+
throw new Error(
170+
`
171+
172+
To be able to use emitCss: true, add
173+
174+
const SveltePlugin = require('svelte-loader').plugin;
175+
176+
to the top of your webpack.config.js and
177+
SveltePlugin to the plugins array like this
178+
179+
plugins: [
180+
...
181+
new SveltePlugin()
182+
]
183+
`.split('\n').map(s => s.slice(5)).join('\n')
184+
);
174185
}
186+
187+
virtualModules.writeModule(cssFilepath, css.code);
175188
}
176189

177190
callback(null, js.code, js.map);
@@ -180,4 +193,15 @@ module.exports = function(source, map) {
180193
// context when logging to console
181194
callback(new Error(`${err.name}: ${err.toString()}`));
182195
});
183-
};
196+
}
197+
198+
class SveltePlugin extends VirtualModules {
199+
apply(compiler) {
200+
virtualModuleInstances.set(compiler, this);
201+
super.apply(compiler);
202+
}
203+
}
204+
205+
loader.plugin = SveltePlugin;
206+
207+
module.exports = loader;

lib/virtual-stats.js

Lines changed: 0 additions & 89 deletions
This file was deleted.

lib/virtual.js

Lines changed: 0 additions & 89 deletions
This file was deleted.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "svelte-loader",
3-
"version": "2.13.6",
3+
"version": "3.0.0",
44
"author": "Nico Rehwaldt <[email protected]>",
55
"description": "A webpack loader for svelte",
66
"license": "MIT",
@@ -16,7 +16,8 @@
1616
],
1717
"dependencies": {
1818
"loader-utils": "^1.1.0",
19-
"svelte-dev-helper": "^1.1.9"
19+
"svelte-dev-helper": "^1.1.9",
20+
"webpack-virtual-modules": "^0.4.1"
2021
},
2122
"devDependencies": {
2223
"chai": "^4.1.2",
@@ -25,7 +26,7 @@
2526
"mocha": "^5.2.0",
2627
"sinon": "^6.1.5",
2728
"sinon-chai": "^3.2.0",
28-
"svelte": "^3.0.0-beta.5"
29+
"svelte": "^3.0.0"
2930
},
3031
"peerDependencies": {
3132
"svelte": ">1.44.0"

test/loader.spec.js

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -208,19 +208,6 @@ describe('loader', () => {
208208
{}
209209
)
210210
);
211-
212-
it(
213-
'should configure emitCss=true',
214-
testLoader(
215-
'test/fixtures/css.html',
216-
function(err, code, map) {
217-
expect(err).not.to.exist;
218-
219-
expect(code).to.match(/import '.+\.css';/);
220-
},
221-
{ emitCss: true }
222-
)
223-
);
224211
});
225212

226213
describe('preprocess', () => {

0 commit comments

Comments
 (0)