svelte-loader
Advanced tools
Comparing version 2.1.0 to 2.2.0
# svelte-loader changelog | ||
## 2.2.0 | ||
* Add `emitCss` option ([#28](https://github.com/sveltejs/svelte-loader/pull/28)) | ||
## 2.1.0 | ||
@@ -4,0 +8,0 @@ |
14
index.js
const { basename, extname } = require('path'); | ||
const { compile } = require('svelte'); | ||
const { getOptions } = require('loader-utils'); | ||
const { statSync, utimesSync, writeFileSync } = require('fs'); | ||
const { fileSync } = require('tmp'); | ||
@@ -31,4 +33,14 @@ function sanitize(input) { | ||
try { | ||
let { code, map } = compile(source, options); | ||
let { code, map, css, cssMap } = compile(source, options); | ||
if (options.emitCss && css) { | ||
const tmpobj = fileSync({ postfix: '.css' }); | ||
css += '\n/*# sourceMappingURL=' + cssMap.toUrl() + '*/'; | ||
code = code + `\nrequire('${tmpobj.name}');\n`; | ||
writeFileSync(tmpobj.name, css); | ||
const stats = statSync(tmpobj.name); | ||
utimesSync(tmpobj.name, stats.atimeMs - 9999, stats.mtimeMs - 9999); | ||
} | ||
this.callback(null, code, map); | ||
@@ -35,0 +47,0 @@ } catch (err) { |
{ | ||
"name": "svelte-loader", | ||
"version": "2.1.0", | ||
"version": "2.2.0", | ||
"author": "Nico Rehwaldt <git_nikku@nixis.de>", | ||
@@ -18,3 +18,4 @@ "description": "A webpack loader for svelte", | ||
"dependencies": { | ||
"loader-utils": "^1.1.0" | ||
"loader-utils": "^1.1.0", | ||
"tmp": "0.0.31" | ||
}, | ||
@@ -21,0 +22,0 @@ "devDependencies": { |
@@ -30,5 +30,90 @@ # svelte-loader | ||
### Extracting CSS | ||
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. | ||
```javascript | ||
... | ||
module: { | ||
rules: [ | ||
... | ||
{ | ||
test: /\.(html|svelte)$/, | ||
exclude: /node_modules/, | ||
use: { | ||
loader: 'svelte-loader', | ||
options: { | ||
emitCss: true, | ||
}, | ||
}, | ||
}, | ||
{ | ||
test: /\.css$/, | ||
use: ExtractTextPlugin.extract({ | ||
fallback: 'style-loader', | ||
use: 'css-loader', | ||
}), | ||
}, | ||
... | ||
] | ||
}, | ||
... | ||
plugins: [ | ||
new ExtractTextPlugin('styles.css'), | ||
... | ||
] | ||
... | ||
``` | ||
Alternatively, if you're handling styles in some other way and just want to prevent the CSS being added to your JavaScript bundle, use `css: false`. | ||
### Source maps | ||
JavaScript source maps are enabled by default, you just have to use an appropriate [webpack devtool](https://webpack.js.org/configuration/devtool/). | ||
To enable CSS source maps, you'll need to use `emitCss` and pass the `sourceMap` option to the `css-loader`. The above config should look like this: | ||
```javascript | ||
module.exports = { | ||
... | ||
devtool: "source-map", // any "source-map"-like devtool is possible | ||
... | ||
module: { | ||
rules: [ | ||
... | ||
{ | ||
test: /\.(html|svelte)$/, | ||
exclude: /node_modules/, | ||
use: { | ||
loader: 'svelte-loader', | ||
options: { | ||
emitCss: true, | ||
}, | ||
}, | ||
}, | ||
{ | ||
test: /\.css$/, | ||
use: ExtractTextPlugin.extract({ | ||
fallback: 'style-loader', | ||
use: [{ loader: 'css-loader', options: { sourceMap: true } }], | ||
}), | ||
}, | ||
... | ||
] | ||
}, | ||
... | ||
plugins: [ | ||
new ExtractTextPlugin('styles.css'), | ||
... | ||
] | ||
... | ||
}; | ||
``` | ||
This should create an additional `styles.css.map` file. | ||
## License | ||
MIT |
@@ -11,2 +11,6 @@ /* global describe, it */ | ||
function d([str]) { | ||
return str.replace(/^\t+/gm, '').trim(); | ||
} | ||
describe('loader', () => { | ||
@@ -56,7 +60,7 @@ function testLoader(fileName, callback, query, version = 2) { | ||
expect(err.message).to.eql( | ||
'ParseError: Expected }}}\n' + | ||
'1: <p>Count: {{{count}}</p>\n' + | ||
' ^\n' + | ||
"2: <button on:click='set({ count: count + 1 })'>+1</button>" | ||
expect(err.message).to.eql(d` | ||
ParseError: Expected }}} | ||
1: <p>Count: {{{count}}</p> | ||
^ | ||
2: <button on:click='set({ count: count + 1 })'>+1</button>` | ||
); | ||
@@ -79,10 +83,10 @@ | ||
expect(err.message).to.eql( | ||
'ParseError: Unexpected token\n' + | ||
'3: <script>\n' + | ||
'4: export {\n' + | ||
"5: foo: 'BAR'\n" + | ||
' ^\n' + | ||
'6: };\n' + | ||
'7: </script>' | ||
expect(err.message).to.eql(d` | ||
ParseError: Unexpected token | ||
3: <script> | ||
4: export { | ||
5: foo: 'BAR' | ||
^ | ||
6: }; | ||
7: </script>` | ||
); | ||
@@ -105,10 +109,10 @@ | ||
expect(err.message).to.eql( | ||
'ValidationError: Computed properties can be function expressions or arrow function expressions\n' + | ||
'4: export default {\n' + | ||
'5: computed: {\n' + | ||
"6: foo: 'BAR'\n" + | ||
' ^\n' + | ||
'7: }\n' + | ||
'8: };' | ||
expect(err.message).to.eql(d` | ||
ValidationError: Computed properties can be function expressions or arrow function expressions | ||
4: export default { | ||
5: computed: { | ||
6: foo: 'BAR' | ||
^ | ||
7: } | ||
8: };` | ||
); | ||
@@ -132,3 +136,3 @@ | ||
// es2015 statements remain | ||
expect(code).to.contain("import { hello } from './utils';"); | ||
expect(code).to.contain(`import { hello } from './utils';`); | ||
expect(code).to.contain('data() {'); | ||
@@ -144,3 +148,3 @@ }) | ||
// es2015 statements remain | ||
expect(code).to.contain("import Nested from './nested';"); | ||
expect(code).to.contain(`import Nested from './nested';`); | ||
@@ -159,3 +163,3 @@ expect(code).to.exist; | ||
expect(err).not.to.exist; | ||
expect(code).to.contain('function add_css ()'); | ||
expect(code).to.contain('function add_css()'); | ||
}) | ||
@@ -170,3 +174,3 @@ ); | ||
expect(err).not.to.exist; | ||
expect(code).not.to.contain('function add_css ()'); | ||
expect(code).not.to.contain('function add_css()'); | ||
}, | ||
@@ -215,3 +219,3 @@ { css: false } | ||
expect(code).not.to.contain('.render = function ( root, options ) {'); | ||
expect(code).not.to.contain('.render = function(state, options = {}) {'); | ||
}) | ||
@@ -227,3 +231,3 @@ ); | ||
expect(code).to.contain('.render = function ( state, options ) {'); | ||
expect(code).to.contain('.render = function(state, options = {}) {'); | ||
}, | ||
@@ -234,2 +238,30 @@ { generate: 'ssr' } | ||
}); | ||
describe('emitCss', function() { | ||
it( | ||
'should configure emitCss=false (default)', | ||
testLoader( | ||
'test/fixtures/css.html', | ||
function(err, code, map) { | ||
expect(err).not.to.exist; | ||
expect(code).not.to.match(/require\('.+\.css'\);/); | ||
}, | ||
{} | ||
) | ||
); | ||
it( | ||
'should configure emitCss=true', | ||
testLoader( | ||
'test/fixtures/css.html', | ||
function(err, code, map) { | ||
expect(err).not.to.exist; | ||
expect(code).to.match(/require\('.+\.css'\);/); | ||
}, | ||
{ emitCss: true } | ||
) | ||
); | ||
}); | ||
}); | ||
@@ -236,0 +268,0 @@ }); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
73965
1314
119
3
32
4
+ Addedtmp@0.0.31
+ Addedos-tmpdir@1.0.2(transitive)
+ Addedtmp@0.0.31(transitive)