From 3e093614dbbebf0e87141c80a221b53544e4bfb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=90=9A=E8=87=B4=E8=BF=9C?= Date: Mon, 18 Jan 2021 12:50:28 +0800 Subject: [PATCH 1/5] Minor grammar improvements to README (#5895) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d1befaf1ce..fa79a4137d 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Learn more at the [Svelte website](https://svelte.dev), or stop by the [Discord ## Supporting Svelte -Svelte is an MIT-licensed open source project with its ongoing development made possible entirely by the support of awesome volunteers. If you'd like to support their efforts, please consider: +Svelte is an MIT-licensed open source project with its ongoing development made possible entirely by fantastic volunteers. If you'd like to support their efforts, please consider: - [Becoming a backer on Open Collective](https://opencollective.com/svelte). @@ -44,7 +44,7 @@ npm install > Do not use Yarn to install the dependencies, as the specific package versions in `package-lock.json` are used to build and test Svelte. -To build the compiler, and all the other modules included in the package: +To build the compiler and all the other modules included in the package: ```bash npm run build @@ -56,7 +56,7 @@ To watch for changes and continually rebuild the package (this is useful if you' npm run dev ``` -The compiler is written in [TypeScript](https://www.typescriptlang.org/), but don't let that put you off — it's basically just JavaScript with type annotations. You'll pick it up in no time. If you're using an editor other than [Visual Studio Code](https://code.visualstudio.com/) you may need to install a plugin in order to get syntax highlighting and code hints etc. +The compiler is written in [TypeScript](https://www.typescriptlang.org/), but don't let that put you off — it's basically just JavaScript with type annotations. You'll pick it up in no time. If you're using an editor other than [Visual Studio Code](https://code.visualstudio.com/), you may need to install a plugin in order to get syntax highlighting and code hints, etc. ### Running Tests From 32775a699dd9cbc9884ee04931c3903b832775d5 Mon Sep 17 00:00:00 2001 From: Domenik Reitzner <30938967+dreitzner@users.noreply.github.com> Date: Mon, 18 Jan 2021 06:24:48 +0100 Subject: [PATCH 2/5] Make TypeScript integration more visible (#5871) --- .../blog/2017-08-07-the-easiest-way-to-get-started.md | 5 +++++ site/src/routes/index.svelte | 2 ++ 2 files changed, 7 insertions(+) diff --git a/site/content/blog/2017-08-07-the-easiest-way-to-get-started.md b/site/content/blog/2017-08-07-the-easiest-way-to-get-started.md index 5fed4b347c..3a25f15b12 100644 --- a/site/content/blog/2017-08-07-the-easiest-way-to-get-started.md +++ b/site/content/blog/2017-08-07-the-easiest-way-to-get-started.md @@ -43,12 +43,17 @@ In the terminal, you can instantly create a new project like so: ```bash npx degit sveltejs/template my-svelte-project cd my-svelte-project +# to use TypeScript run: +# node scripts/setupTypeScript.js + npm install npm run dev ``` This will create a new project in the `my-svelte-project` directory, install its dependencies, and start a server on http://localhost:5000. +You can find more information about using TypeScript [here](blog/svelte-and-typescript). + Once you've tinkered a bit and understood how everything fits together, you can fork [sveltejs/template](https://github.com/sveltejs/template) and start doing this instead: ```bash diff --git a/site/src/routes/index.svelte b/site/src/routes/index.svelte index af8afefbb7..3c84d6ea15 100644 --- a/site/src/routes/index.svelte +++ b/site/src/routes/index.svelte @@ -77,6 +77,8 @@ npx degit sveltejs/template my-svelte-project # or download and extract this .zip file cd my-svelte-project +# to use TypeScript run: +# node scripts/setupTypeScript.js npm install npm run dev From dbd184c38c0f517107316835db948619ff4cf8c0 Mon Sep 17 00:00:00 2001 From: Manuel B Date: Mon, 18 Jan 2021 20:46:51 +0100 Subject: [PATCH 3/5] Add a linguist configuration (#5878) --- .gitattributes | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..a299a4435a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +/site/** -linguist-detectable +/test/**/samples/** -linguist-detectable +/**/*.svelte linguist-detectable From 0d19f67ec40e4ba4275e837451f28b97755ce12f Mon Sep 17 00:00:00 2001 From: milahu Date: Tue, 19 Jan 2021 18:53:10 +0100 Subject: [PATCH 4/5] Parse attached sourcemap from preprocessor (#5854) --- src/compiler/preprocess/index.ts | 14 ++++-- src/compiler/utils/string_with_sourcemap.ts | 38 ++++++++++++++++ test/sourcemaps/index.ts | 11 +++-- .../samples/attached-sourcemap/_config.js | 44 ++++++++++++++++++ .../samples/attached-sourcemap/input.svelte | 11 +++++ .../samples/attached-sourcemap/test.js | 45 +++++++++++++++++++ 6 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 test/sourcemaps/samples/attached-sourcemap/_config.js create mode 100644 test/sourcemaps/samples/attached-sourcemap/input.svelte create mode 100644 test/sourcemaps/samples/attached-sourcemap/test.js diff --git a/src/compiler/preprocess/index.ts b/src/compiler/preprocess/index.ts index 264fbbdbcd..e0847898d5 100644 --- a/src/compiler/preprocess/index.ts +++ b/src/compiler/preprocess/index.ts @@ -1,7 +1,12 @@ import { RawSourceMap, DecodedSourceMap } from '@ampproject/remapping/dist/types/types'; import { decode as decode_mappings } from 'sourcemap-codec'; import { getLocator } from 'locate-character'; -import { StringWithSourcemap, sourcemap_add_offset, combine_sourcemaps } from '../utils/string_with_sourcemap'; +import { + StringWithSourcemap, + sourcemap_add_offset, + combine_sourcemaps, + parse_attached_sourcemap +} from '../utils/string_with_sourcemap'; export interface Processed { code: string; @@ -170,7 +175,8 @@ function get_replacement( original: string, processed: Processed, prefix: string, - suffix: string + suffix: string, + tag_name: 'script' | 'style' ): StringWithSourcemap { // Convert the unchanged prefix and suffix to StringWithSourcemap @@ -179,6 +185,8 @@ function get_replacement( const suffix_with_map = StringWithSourcemap.from_source( file_basename, suffix, get_location(offset + prefix.length + original.length)); + parse_attached_sourcemap(processed, tag_name); + // Convert the preprocessed code and its sourcemap to a StringWithSourcemap let decoded_map: DecodedSourceMap; if (processed.map) { @@ -282,7 +290,7 @@ export default async function preprocess( if (!processed || !processed.map && processed.code === content) { return no_change(); } - return get_replacement(file_basename, offset, get_location, content, processed, `<${tag_name}${attributes}>`, ``); + return get_replacement(file_basename, offset, get_location, content, processed, `<${tag_name}${attributes}>`, ``, tag_name); } ); source = res.string; diff --git a/src/compiler/utils/string_with_sourcemap.ts b/src/compiler/utils/string_with_sourcemap.ts index 1766a0db06..3002e10d84 100644 --- a/src/compiler/utils/string_with_sourcemap.ts +++ b/src/compiler/utils/string_with_sourcemap.ts @@ -1,6 +1,7 @@ import { DecodedSourceMap, RawSourceMap, SourceMapLoader } from '@ampproject/remapping/dist/types/types'; import remapping from '@ampproject/remapping'; import { SourceMap } from 'magic-string'; +import { Processed } from '../preprocess'; type SourceLocation = { line: number; @@ -255,6 +256,7 @@ export function combine_sourcemaps( // browser vs node.js const b64enc = typeof btoa == 'function' ? btoa : b => Buffer.from(b).toString('base64'); +const b64dec = typeof atob == 'function' ? atob : a => Buffer.from(a, 'base64').toString(); export function apply_preprocessor_sourcemap(filename: string, svelte_map: SourceMap, preprocessor_map_input: string | DecodedSourceMap | RawSourceMap): SourceMap { if (!svelte_map || !preprocessor_map_input) return svelte_map; @@ -288,3 +290,39 @@ export function apply_preprocessor_sourcemap(filename: string, svelte_map: Sourc return result_map as SourceMap; } + +// parse attached sourcemap in processed.code +export function parse_attached_sourcemap(processed: Processed, tag_name: 'script' | 'style'): void { + const r_in = '[#@]\\s*sourceMappingURL\\s*=\\s*(\\S*)'; + const regex = (tag_name == 'script') + ? new RegExp('(?://'+r_in+')|(?:/\\*'+r_in+'\\s*\\*/)$') + : new RegExp('/\\*'+r_in+'\\s*\\*/$'); + function log_warning(message) { + // code_start: help to find preprocessor + const code_start = processed.code.length < 100 ? processed.code : (processed.code.slice(0, 100) + ' [...]'); + console.warn(`warning: ${message}. processed.code = ${JSON.stringify(code_start)}`); + } + processed.code = processed.code.replace(regex, (_, match1, match2) => { + const map_url = (tag_name == 'script') ? (match1 || match2) : match1; + const map_data = (map_url.match(/data:(?:application|text)\/json;(?:charset[:=]\S+?;)?base64,(\S*)/) || [])[1]; + if (map_data) { + // sourceMappingURL is data URL + if (processed.map) { + log_warning('Not implemented. ' + + 'Found sourcemap in both processed.code and processed.map. ' + + 'Please update your preprocessor to return only one sourcemap.'); + // ignore attached sourcemap + return ''; + } + processed.map = b64dec(map_data); // use attached sourcemap + return ''; // remove from processed.code + } + // sourceMappingURL is path or URL + if (!processed.map) { + log_warning(`Found sourcemap path ${JSON.stringify(map_url)} in processed.code, but no sourcemap data. ` + + 'Please update your preprocessor to return sourcemap data directly.'); + } + // ignore sourcemap path + return ''; // remove from processed.code + }); +} diff --git a/test/sourcemaps/index.ts b/test/sourcemaps/index.ts index 4122c3a419..903629c06b 100644 --- a/test/sourcemaps/index.ts +++ b/test/sourcemaps/index.ts @@ -31,7 +31,8 @@ describe('sourcemaps', () => { const inputCode = fs.readFileSync(inputFile, 'utf-8'); const input = { code: inputCode, - locate: getLocator(inputCode) + locate: getLocator(inputCode), + locate_1: getLocator(inputCode, { offsetLine: 1 }) }; const preprocessed = await svelte.preprocess( @@ -41,7 +42,7 @@ describe('sourcemaps', () => { filename: 'input.svelte' } ); - + const { js, css } = svelte.compile( preprocessed.code, { filename: 'input.svelte', @@ -86,12 +87,14 @@ describe('sourcemaps', () => { assert.deepEqual( js.map.sources.slice().sort(), - (config.js_map_sources || ['input.svelte']).sort() + (config.js_map_sources || ['input.svelte']).sort(), + 'js.map.sources is wrong' ); if (css.map) { assert.deepEqual( css.map.sources.slice().sort(), - (config.css_map_sources || ['input.svelte']).sort() + (config.css_map_sources || ['input.svelte']).sort(), + 'css.map.sources is wrong' ); } diff --git a/test/sourcemaps/samples/attached-sourcemap/_config.js b/test/sourcemaps/samples/attached-sourcemap/_config.js new file mode 100644 index 0000000000..6d9786f6b0 --- /dev/null +++ b/test/sourcemaps/samples/attached-sourcemap/_config.js @@ -0,0 +1,44 @@ +import MagicString from 'magic-string'; + +let indent_size = 4; +let comment_multi = true; +function get_processor(tag_name, search, replace) { + return { + [tag_name]: ({ content, filename }) => { + let code = content.slice(); + const ms = new MagicString(code); + + const idx = ms.original.indexOf(search); + if (idx == -1) throw new Error('search not found in src'); + ms.overwrite(idx, idx + search.length, replace, { storeName: true }); + + // change line + column + const indent = Array.from({ length: indent_size }).join(' '); + ms.prependLeft(idx, '\n'+indent); + + const map_opts = { source: filename, hires: true, includeContent: false }; + const map = ms.generateMap(map_opts); + const attach_line = (tag_name == 'style' || comment_multi) + ? `\n/*# sourceMappingURL=${map.toUrl()} */` + : `\n//# sourceMappingURL=${map.toUrl()}` // only in script + ; + code = ms.toString() + attach_line; + + indent_size += 2; + if (tag_name == 'script') comment_multi = !comment_multi; + return { code }; + } + }; +} + +export default { + preprocess: [ + + get_processor('script', 'replace_me_script', 'done_replace_script_1'), + get_processor('script', 'done_replace_script_1', 'done_replace_script_2'), + + get_processor('style', '.replace_me_style', '.done_replace_style_1'), + get_processor('style', '.done_replace_style_1', '.done_replace_style_2') + + ] +}; diff --git a/test/sourcemaps/samples/attached-sourcemap/input.svelte b/test/sourcemaps/samples/attached-sourcemap/input.svelte new file mode 100644 index 0000000000..21a47a72a9 --- /dev/null +++ b/test/sourcemaps/samples/attached-sourcemap/input.svelte @@ -0,0 +1,11 @@ + + +

{done_replace_script_2}

diff --git a/test/sourcemaps/samples/attached-sourcemap/test.js b/test/sourcemaps/samples/attached-sourcemap/test.js new file mode 100644 index 0000000000..c5b4d7989d --- /dev/null +++ b/test/sourcemaps/samples/attached-sourcemap/test.js @@ -0,0 +1,45 @@ +import * as assert from 'assert'; + +const get_line_column = obj => ({ line: obj.line, column: obj.column }); + +export function test({ input, css, js }) { + + let out_obj, loc_output, actual, loc_input, expected; + + out_obj = js; + // we need the second occurence of 'done_replace_script_2' in output.js + // the first occurence is mapped back to markup '{done_replace_script_2}' + loc_output = out_obj.locate_1('done_replace_script_2'); + loc_output = out_obj.locate_1('done_replace_script_2', loc_output.character + 1); + actual = out_obj.mapConsumer.originalPositionFor(loc_output); + loc_input = input.locate_1('replace_me_script'); + expected = { + source: 'input.svelte', + name: 'replace_me_script', + ...get_line_column(loc_input) + }; + assert.deepEqual(actual, expected); + + out_obj = css; + loc_output = out_obj.locate_1('.done_replace_style_2'); + actual = out_obj.mapConsumer.originalPositionFor(loc_output); + loc_input = input.locate_1('.replace_me_style'); + expected = { + source: 'input.svelte', + name: '.replace_me_style', + ...get_line_column(loc_input) + }; + assert.deepEqual(actual, expected); + + assert.equal( + js.code.indexOf('\n/*# sourceMappingURL=data:application/json;base64,'), + -1, + 'magic-comment attachments were NOT removed' + ); + + assert.equal( + css.code.indexOf('\n/*# sourceMappingURL=data:application/json;base64,'), + -1, + 'magic-comment attachments were NOT removed' + ); +} From 8364048d95db25c33a116348276434cb1d046846 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Wed, 20 Jan 2021 09:35:34 +0100 Subject: [PATCH 5/5] Update unreleased --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0057292c22..24ae2f5d28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Svelte changelog +## Unreleased + + +* Support attached sourcemaps as magic comment inside code from preprocessors ([#5854](https://github.com/sveltejs/svelte/pull/5854)) + ## 3.31.2 * Rework SSR store handling to subscribe and unsubscribe as in DOM mode ([#3375](https://github.com/sveltejs/svelte/issues/3375), [#3582](https://github.com/sveltejs/svelte/issues/3582), [#3636](https://github.com/sveltejs/svelte/issues/3636))