Skip to content

break: remove css option #147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Nov 23, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 2 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,6 @@ export default {
// your components to custom elements (aka web elements)
customElement: false,

// Extract CSS into a single bundled file (recommended).
// See note below
css: function (css) {
console.log(css.code); // the concatenated CSS
console.log(css.map); // a sourcemap

// creates `main.css` and `main.css.map`
// using a falsy name will default to the bundle name
// — pass `false` as the second argument if you don't want the sourcemap
css.write('main.css');
},

// Warnings are normally passed straight to Rollup. You can
// optionally handle them here, for example to squelch
// warnings with a particular code
Expand Down Expand Up @@ -120,11 +108,9 @@ and so on. Then, in `package.json`, set the `svelte` property to point to this `

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 `css` option as shown above would cause a `public/main.css` file to be generated each time the bundle is built (or rebuilt, if you're using rollup-watch), with the normal scoping rules applied.

If you have other plugins processing your CSS (e.g. rollup-plugin-scss), and want your styles passed through to them to be bundled together, you can use `emitCss: true`.
A better option is to emit the CSS styles into a virtual file (via `emitCss: true`), allowing another Rollup plugin – for example, [`rollup-plugin-css-only`](https://www.npmjs.com/package/rollup-plugin-css-only), [`rollup-plugin-postcss`](https://www.npmjs.com/package/rollup-plugin-postcss), etc. – to take responsibility for the new stylesheet.

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`.
In fact, emitting CSS files _requires_ that you use a Rollup plugin to handle the CSS. Otherwise, your build(s) will fail!


## License
Expand Down
5 changes: 1 addition & 4 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,9 @@ interface Options {
// }
// },

/** Emit CSS as "files" for other plugins to process */
/** Emit Svelte styles as virtual CSS files for other plugins to process. */
emitCss: boolean;

/** Extract CSS into a separate file (recommended) */
css: false | CssEmitter;

/** Options passed to `svelte.compile` method. */
compilerOptions: CompileOptions;

Expand Down
150 changes: 19 additions & 131 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,84 +2,15 @@ const path = require('path');
const relative = require('require-relative');
const { createFilter } = require('rollup-pluginutils');
const { compile, preprocess } = require('svelte/compiler');
const { encode, decode } = require('sourcemap-codec');

const PREFIX = '[rollup-plugin-svelte]';
const pkg_export_errors = new Set();

const plugin_options = new Set([
'include', 'exclude', 'extensions',
'preprocess', 'onwarn',
'emitCss', 'css',
'preprocess', 'onwarn', 'emitCss',
]);

function to_entry_css(bundle) {
for (let file in bundle) {
let { name } = path.parse(file);
return name + '.css';
}
}

class CssWriter {
constructor(context, bundle, isDev, code, map) {
this.code = code;
this.filename = to_entry_css(bundle);

this.map = map && {
version: 3,
file: null,
sources: map.sources,
sourcesContent: map.sourcesContent,
names: [],
mappings: encode(map.mappings)
};

this.warn = context.warn;
this.emit = (name, source) => context.emitFile({
type: 'asset', name, source
});

this.sourcemap = (file, mapping) => {
const ref = this.emit(file, this.code);
const filename = context.getFileName(ref); // may be "assets/[name][ext]"

const mapfile = `${filename}.map`; // may be "assets/[name][ext]"
const toRelative = src => path.relative(path.dirname(file), src);

if (bundle[filename]) {
// use `basename` because files are siblings
// aka, avoid `sourceMappingURL=assets/bundle.css.map` from `assets/bundle.css`
bundle[filename].source += `\n/*# sourceMappingURL=${path.basename(mapfile)} */`;
} else {
// This should not ever happen, but just in case...
return this.warn(`Missing "${filename}" ("${file}") in bundle; skipping sourcemap!`);
}

const source = JSON.stringify({
...mapping,
file: path.basename(filename), //=> sibling file
sources: mapping.sources.map(toRelative),
}, null, isDev ? 2 : 0);

// use `fileName` to prevent additional Rollup hashing
context.emitFile({ type: 'asset', fileName: mapfile, source });
};
}

write(dest = this.filename, map = !!this.map) {
if (map && this.map) {
this.sourcemap(dest, this.map);
} else {
this.emit(dest, this.code);
}
}

toString() {
this.warn('[DEPRECATION] As of rollup-plugin-svelte@3, the argument to the `css` function is an object, not a string — use `css.write(file)`. Consult the documentation for more information: https://github.com/rollup/rollup-plugin-svelte');
return this.code;
}
}

/**
* @param [options] {Partial<import('.').Options>}
* @returns {import('rollup').Plugin}
Expand All @@ -90,34 +21,31 @@ module.exports = function (options = {}) {
const filter = createFilter(rest.include, rest.exclude);

compilerOptions.format = 'esm';
const isDev = !!compilerOptions.dev;

for (let key in rest) {
if (plugin_options.has(key)) continue;
console.warn(`${PREFIX} Unknown "${key}" option. Please use "compilerOptions" for any Svelte compiler configuration.`);
}

const css_cache = new Map(); // [filename]:[chunk]
const { css, emitCss, onwarn } = rest;
// [filename]:[chunk]
const cache_emit = new Map;
const { emitCss, onwarn } = rest;

const ctype = typeof css;
const toWrite = ctype === 'function' && css;
if (css != null && !toWrite && ctype !== 'boolean') {
throw new Error('options.css must be a boolean or a function');
if (emitCss) {
if (compilerOptions.css) {
console.warn(`${PREFIX} Forcing \`"compilerOptions.css": false\` because "emitCss" was truthy.`);
}
compilerOptions.css = false;
}

// block svelte's inline CSS if writer
const external_css = !!(toWrite || emitCss);
if (external_css) compilerOptions.css = false;

return {
name: 'svelte',

/**
* Resolve an import's full filepath.
*/
resolveId(importee, importer) {
if (css_cache.has(importee)) return importee;
if (cache_emit.has(importee)) return importee;
if (!importer || importee[0] === '.' || importee[0] === '\0' || path.isAbsolute(importee)) return null;

// if this is a bare import, see if there's a valid pkg.svelte
Expand Down Expand Up @@ -152,12 +80,12 @@ module.exports = function (options = {}) {
* Returns CSS contents for a file, if ours
*/
load(id) {
return css_cache.get(id) || null;
return cache_emit.get(id) || null;
},

/**
* Transforms a `.svelte` file into a `.js` file.
* NOTE: If `emitCss: true`, appends a static `import` for virtual CSS file.
* NOTE: If `emitCss`, append static `import` to virtual CSS file.
*/
async transform(code, id) {
if (!filter(id)) return null;
Expand All @@ -177,20 +105,16 @@ module.exports = function (options = {}) {
const compiled = compile(code, { ...compilerOptions, filename });

(compiled.warnings || []).forEach(warning => {
if (!css && !emitCss && warning.code === 'css-unused-selector') return;
if (!emitCss && warning.code === 'css-unused-selector') return;
if (onwarn) onwarn(warning, this.warn);
else this.warn(warning);
});

if (external_css && compiled.css.code) {
if (emitCss && compiled.css.code) {
const fname = id.replace(new RegExp(`\\${extension}$`), '.css');

if (emitCss) {
compiled.js.code += `\nimport ${JSON.stringify(fname)};\n`;
compiled.css.code += `\n/*# sourceMappingURL=${compiled.css.map.toUrl()} */`;
}

css_cache.set(fname, compiled.css);
compiled.css.code += `\n/*# sourceMappingURL=${compiled.css.map.toUrl()} */`;
compiled.js.code += `\nimport ${JSON.stringify(fname)};\n`;
cache_emit.set(fname, compiled.css);
}

if (this.addWatchFile) {
Expand All @@ -203,49 +127,13 @@ module.exports = function (options = {}) {
},

/**
* Write to CSS file if given `options.css` function.
* TODO: is there a better way to concat/append into Rollup asset?
* All resolutions done; display warnings wrt `package.json` access.
*/
generateBundle(config, bundle) {
generateBundle() {
if (pkg_export_errors.size > 0) {
console.warn(`\n${PREFIX} The following packages did not export their \`package.json\` file so we could not check the "svelte" field. If you had difficulties importing svelte components from a package, then please contact the author and ask them to export the package.json file.\n`);
console.warn(Array.from(pkg_export_errors, s => `- ${s}`).join('\n') + '\n');
}

if (!toWrite) return;

let result = '';
const sources = [];
const sourcesContent = config.sourcemapExcludeSources ? null : [];
const mappings = [];

[...css_cache.keys()].sort().forEach(file => {
const chunk = css_cache.get(file);
if (!chunk.code) return;

result += chunk.code + '\n';

if (config.sourcemap && chunk.map) {
const len = sources.length;
sources.push(...chunk.map.sources);
if (sourcesContent) sourcesContent.push(...chunk.map.sourcesContent);

const decoded = decode(chunk.map.mappings);

if (len > 0) {
decoded.forEach(line => {
line.forEach(segment => {
segment[1] += len;
});
});
}

mappings.push(...decoded);
}
});

const sourceMap = config.sourcemap && { sources, sourcesContent, mappings };
toWrite(new CssWriter(this, bundle, isDev, result, sourceMap));
}
};
};
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,14 @@
},
"dependencies": {
"require-relative": "^0.8.7",
"rollup-pluginutils": "^2.8.2",
"sourcemap-codec": "^1.4.8"
"rollup-pluginutils": "^2.8.2"
},
"peerDependencies": {
"svelte": ">=3.5.0",
"rollup": ">=2.0.0"
},
"devDependencies": {
"eslint": "^6.8.0",
"locate-character": "^2.0.5",
"rollup": "^2.30.0",
"sander": "^0.6.0",
"source-map": "^0.7.3",
Expand Down
3 changes: 1 addition & 2 deletions test/filename-test/expected/bundle.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 0 additions & 12 deletions test/filename-test/expected/bundle.css.map

This file was deleted.

Loading