diff --git a/site/content/docs/04-compile-time.md b/site/content/docs/04-compile-time.md index ed6977f81fc8..8e709d7c37cc 100644 --- a/site/content/docs/04-compile-time.md +++ b/site/content/docs/04-compile-time.md @@ -82,6 +82,8 @@ The following options can be passed to the compiler. None are required: | `loopGuardTimeout` | 0 | A `number` that tells Svelte to break the loop if it blocks the thread for more than `loopGuardTimeout` ms. This is useful to prevent infinite loops. **Only available when `dev: true`** | `preserveComments` | `false` | If `true`, your HTML comments will be preserved during server-side rendering. By default, they are stripped out. | `preserveWhitespace` | `false` | If `true`, whitespace inside and between elements is kept as you typed it, rather than removed or collapsed to a single space where possible. +| `sourcemap` | `object | string` | An initial sourcemap that will be merged into the final output sourcemap. This is usually the preprocessor sourcemap. +| `enableSourcemap` | `boolean | { js: boolean; css: boolean; }` | If `true`, Svelte generate sourcemaps for components. Use an object with `js` or `css` for more granular control of sourcemap generation. By default, this is `true`. | `outputFilename` | `null` | A `string` used for your JavaScript sourcemap. | `cssOutputFilename` | `null` | A `string` used for your CSS sourcemap. | `sveltePath` | `"svelte"` | The location of the `svelte` package. Any imports from `svelte` or `svelte/[module]` will be modified accordingly. diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index 202e14fd9813..4d4cf909fda6 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -36,6 +36,7 @@ import { clone } from '../utils/clone'; import compiler_warnings from './compiler_warnings'; import compiler_errors from './compiler_errors'; import { extract_ignores_above_position, extract_svelte_ignore_from_comments } from '../utils/extract_svelte_ignore'; +import check_enable_sourcemap from './utils/check_enable_sourcemap'; interface ComponentOptions { namespace?: string; @@ -343,21 +344,28 @@ export default class Component { ? { code: null, map: null } : result.css; - const sourcemap_source_filename = get_sourcemap_source_filename(compile_options); + const js_sourcemap_enabled = check_enable_sourcemap(compile_options.enableSourcemap, 'js'); - js = print(program, { - sourceMapSource: sourcemap_source_filename - }); + if (!js_sourcemap_enabled) { + js = print(program); + js.map = null; + } else { + const sourcemap_source_filename = get_sourcemap_source_filename(compile_options); - js.map.sources = [ - sourcemap_source_filename - ]; + js = print(program, { + sourceMapSource: sourcemap_source_filename + }); - js.map.sourcesContent = [ - this.source - ]; + js.map.sources = [ + sourcemap_source_filename + ]; - js.map = apply_preprocessor_sourcemap(sourcemap_source_filename, js.map, compile_options.sourcemap as (string | RawSourceMap | DecodedSourceMap)); + js.map.sourcesContent = [ + this.source + ]; + + js.map = apply_preprocessor_sourcemap(sourcemap_source_filename, js.map, compile_options.sourcemap as (string | RawSourceMap | DecodedSourceMap)); + } } return { diff --git a/src/compiler/compile/index.ts b/src/compiler/compile/index.ts index 96b24bceeed8..afe9c56cf4ca 100644 --- a/src/compiler/compile/index.ts +++ b/src/compiler/compile/index.ts @@ -13,6 +13,7 @@ const valid_options = [ 'name', 'filename', 'sourcemap', + 'enableSourcemap', 'generate', 'errorMode', 'varsReport', @@ -82,7 +83,7 @@ function validate_options(options: CompileOptions, warnings: Warning[]) { } export default function compile(source: string, options: CompileOptions = {}) { - options = Object.assign({ generate: 'dom', dev: false }, options); + options = Object.assign({ generate: 'dom', dev: false, enableSourcemap: true }, options); const stats = new Stats(); const warnings = []; diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index f74f4cdf1ccb..89af0c297c51 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -10,6 +10,7 @@ import { ImportDeclaration, ClassDeclaration, FunctionExpression, Node, Statemen import { apply_preprocessor_sourcemap } from '../../utils/mapped_code'; import { RawSourceMap, DecodedSourceMap } from '@ampproject/remapping/dist/types/types'; import { flatten } from '../../utils/flatten'; +import check_enable_sourcemap from '../utils/check_enable_sourcemap'; export default function dom( component: Component, @@ -34,9 +35,15 @@ export default function dom( const css = component.stylesheet.render(options.filename, !options.customElement); - css.map = apply_preprocessor_sourcemap(options.filename, css.map, options.sourcemap as string | RawSourceMap | DecodedSourceMap); + const css_sourcemap_enabled = check_enable_sourcemap(options.enableSourcemap, 'css'); - const styles = component.stylesheet.has_styles && options.dev + if (css_sourcemap_enabled) { + css.map = apply_preprocessor_sourcemap(options.filename, css.map, options.sourcemap as string | RawSourceMap | DecodedSourceMap); + } else { + css.map = null; + } + + const styles = css_sourcemap_enabled && component.stylesheet.has_styles && options.dev ? `${css.code}\n/*# sourceMappingURL=${css.map.toUrl()} */` : css.code; @@ -521,7 +528,7 @@ export default function dom( constructor(options) { super(); - ${css.code && b`this.shadowRoot.innerHTML = \`\`;`} + ${css.code && b`this.shadowRoot.innerHTML = \`\`;`} @init(this, { target: this.shadowRoot, props: ${init_props}, customElement: true }, ${definition}, ${has_create_fragment ? 'create_fragment' : 'null'}, ${not_equal}, ${prop_indexes}, null, ${dirty}); diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index b35a6ce6ffee..9d2c1cc60b68 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -10,6 +10,7 @@ import { extract_names } from 'periscopic'; import { walk } from 'estree-walker'; import { invalidate } from '../render_dom/invalidate'; +import check_enable_sourcemap from '../utils/check_enable_sourcemap'; export default function ssr( component: Component, @@ -200,11 +201,13 @@ export default function ssr( main ].filter(Boolean); + const css_sourcemap_enabled = check_enable_sourcemap(options.enableSourcemap, 'css'); + const js = b` ${css.code ? b` const #css = { code: "${css.code}", - map: ${css.map ? string_literal(css.map.toString()) : 'null'} + map: ${css_sourcemap_enabled && css.map ? string_literal(css.map.toString()) : 'null'} };` : null} ${component.extract_javascript(component.ast.module)} diff --git a/src/compiler/compile/utils/check_enable_sourcemap.ts b/src/compiler/compile/utils/check_enable_sourcemap.ts new file mode 100644 index 000000000000..51f07c353ac1 --- /dev/null +++ b/src/compiler/compile/utils/check_enable_sourcemap.ts @@ -0,0 +1,10 @@ +import { EnableSourcemap } from '../../interfaces'; + +export default function check_enable_sourcemap( + enable_sourcemap: EnableSourcemap, + namespace: keyof Extract +) { + return typeof enable_sourcemap === 'boolean' + ? enable_sourcemap + : enable_sourcemap[namespace]; +} diff --git a/src/compiler/interfaces.ts b/src/compiler/interfaces.ts index 7446c4c14b57..b999fbd803dd 100644 --- a/src/compiler/interfaces.ts +++ b/src/compiler/interfaces.ts @@ -131,6 +131,8 @@ export interface Warning { export type ModuleFormat = 'esm' | 'cjs'; +export type EnableSourcemap = boolean | { js: boolean; css: boolean }; + export type CssHashGetter = (args: { name: string; filename: string | undefined; @@ -147,6 +149,7 @@ export interface CompileOptions { varsReport?: 'full' | 'strict' | false; sourcemap?: object | string; + enableSourcemap?: EnableSourcemap; outputFilename?: string; cssOutputFilename?: string; sveltePath?: string; diff --git a/test/sourcemaps/index.ts b/test/sourcemaps/index.ts index 903629c06b1b..fc021cd6a7ca 100644 --- a/test/sourcemaps/index.ts +++ b/test/sourcemaps/index.ts @@ -85,11 +85,13 @@ describe('sourcemaps', () => { ); } - assert.deepEqual( - js.map.sources.slice().sort(), - (config.js_map_sources || ['input.svelte']).sort(), - 'js.map.sources is wrong' - ); + if (js.map) { + assert.deepEqual( + js.map.sources.slice().sort(), + (config.js_map_sources || ['input.svelte']).sort(), + 'js.map.sources is wrong' + ); + } if (css.map) { assert.deepEqual( css.map.sources.slice().sort(), diff --git a/test/sourcemaps/samples/no-sourcemap/_config.js b/test/sourcemaps/samples/no-sourcemap/_config.js new file mode 100644 index 000000000000..5b84d4055408 --- /dev/null +++ b/test/sourcemaps/samples/no-sourcemap/_config.js @@ -0,0 +1,5 @@ +export default { + compile_options: { + enableSourcemap: false + } +}; diff --git a/test/sourcemaps/samples/no-sourcemap/input.svelte b/test/sourcemaps/samples/no-sourcemap/input.svelte new file mode 100644 index 000000000000..6d39eaad0e79 --- /dev/null +++ b/test/sourcemaps/samples/no-sourcemap/input.svelte @@ -0,0 +1,11 @@ + + +

{foo}

+ + diff --git a/test/sourcemaps/samples/no-sourcemap/test.js b/test/sourcemaps/samples/no-sourcemap/test.js new file mode 100644 index 000000000000..127459a54e6e --- /dev/null +++ b/test/sourcemaps/samples/no-sourcemap/test.js @@ -0,0 +1,4 @@ +export function test({ assert, js, css }) { + assert.equal(js.map, null); + assert.equal(css.map, null); +} diff --git a/test/sourcemaps/samples/only-css-sourcemap/_config.js b/test/sourcemaps/samples/only-css-sourcemap/_config.js new file mode 100644 index 000000000000..767e10a4b9af --- /dev/null +++ b/test/sourcemaps/samples/only-css-sourcemap/_config.js @@ -0,0 +1,5 @@ +export default { + compile_options: { + enableSourcemap: { css: true } + } +}; diff --git a/test/sourcemaps/samples/only-css-sourcemap/input.svelte b/test/sourcemaps/samples/only-css-sourcemap/input.svelte new file mode 100644 index 000000000000..6d39eaad0e79 --- /dev/null +++ b/test/sourcemaps/samples/only-css-sourcemap/input.svelte @@ -0,0 +1,11 @@ + + +

{foo}

+ + diff --git a/test/sourcemaps/samples/only-css-sourcemap/test.js b/test/sourcemaps/samples/only-css-sourcemap/test.js new file mode 100644 index 000000000000..a7ac6a9b0bdd --- /dev/null +++ b/test/sourcemaps/samples/only-css-sourcemap/test.js @@ -0,0 +1,4 @@ +export function test({ assert, js, css }) { + assert.equal(js.map, null); + assert.notEqual(css.map, null); +} diff --git a/test/sourcemaps/samples/only-js-sourcemap/_config.js b/test/sourcemaps/samples/only-js-sourcemap/_config.js new file mode 100644 index 000000000000..0b3b7987f174 --- /dev/null +++ b/test/sourcemaps/samples/only-js-sourcemap/_config.js @@ -0,0 +1,5 @@ +export default { + compile_options: { + enableSourcemap: { js: true } + } +}; diff --git a/test/sourcemaps/samples/only-js-sourcemap/input.svelte b/test/sourcemaps/samples/only-js-sourcemap/input.svelte new file mode 100644 index 000000000000..6d39eaad0e79 --- /dev/null +++ b/test/sourcemaps/samples/only-js-sourcemap/input.svelte @@ -0,0 +1,11 @@ + + +

{foo}

+ + diff --git a/test/sourcemaps/samples/only-js-sourcemap/test.js b/test/sourcemaps/samples/only-js-sourcemap/test.js new file mode 100644 index 000000000000..b150653c3d72 --- /dev/null +++ b/test/sourcemaps/samples/only-js-sourcemap/test.js @@ -0,0 +1,4 @@ +export function test({ assert, js, css }) { + assert.notEqual(js.map, null); + assert.equal(css.map, null); +}