Skip to content
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

Add source maps #681

Merged
merged 3 commits into from
Aug 5, 2020
Merged

Add source maps #681

merged 3 commits into from
Aug 5, 2020

Conversation

drwpow
Copy link
Collaborator

@drwpow drwpow commented Jul 31, 2020

Changes

Adds supports for source maps (#666) via the following:

  • @snowpack/plugin-babel: now Lit Element, Preact, and React all get source map support in build & dev
  • @snowpack/plugin-svelte: Svelte, too
  • @snowpack/plugin-vue: …and Vue!
  • esbuild: with blank templates, esbuild will generate source maps if it can, if another compiler like Babel, Vue, or Svelte isn’t being used

It also adds source map support in the dev server.

Screenshot

Here you can see source maps in the dev server! (this also removes some 404 errors for source maps)

Screen Shot 2020-08-03 at 5 25 08 PM

Testing

Some shiny, new .map files were added to the snapshots! 🎉

@drwpow drwpow requested a review from a team as a code owner July 31, 2020 04:51
@vercel
Copy link

vercel bot commented Jul 31, 2020

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/pikapkg/snowpack/my5tolaav
✅ Preview: https://snowpack-git-drwpow-source-maps.pikapkg.vercel.app

Copy link
Owner

@FredKSchott FredKSchott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on the interface work and testing improvements, but lets think through the behavior a bit more. I think we'll make fewer mistakes here if think through this starting from the perspective of supporting plugins first, and then adding support for the minification story after that.

allFilesToResolveImports[outLoc] = {baseExt, expandedExt, contents, locOnDisk};
break;

for (const [fileExt, buildResult] of Object.entries(builtFileOutput)) {
Copy link
Collaborator Author

@drwpow drwpow Aug 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Big core Change

I’m not sure if we were doing this intentionally or not, but it seemed here we were going against our own design. We weren’t respecting our own build map, it seemed.

When a plugin has multiple outputs (e.g. for Svelte in this PR: .js, .js.map, .css, .css.map), we were only doing one pass for all of those! So at first, adding a .js.map to the output didn’t generate anything at all 😅. The reason we didn’t notice was because we were manually writing .css files, and we were only testing the .js + .css output case before.

This changes this logic to now write all keys of the file, which I think is better. But the question is: will this likely break any legacy plugins? I think not, but wanted to flag it.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah good catch! Yup, I bet we just grabbed our old logic here without updating it to the new build map format. This should be good to merge, I can't think of what it could be breaking that isn't already broken

case '.js': {
if (builtFileOutput['.css']) {
await fs.mkdir(path.dirname(cssOutPath), {recursive: true});
await fs.writeFile(cssOutPath, builtFileOutput['.css'], 'utf-8');
Copy link
Collaborator Author

@drwpow drwpow Aug 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above comment: we now handle .css in its own pass, so the writeFile below is all that’s needed now. I think the end result is cleaner / easier to follow.

body{margin:0;font-family:Arial, Helvetica, sans-serif}.App.svelte-12f0jfw{text-align:center}.App-header.svelte-12f0jfw{background-color:#F9F6F6;color:#333;min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;font-size:calc(10px + 2vmin)}.App-link.svelte-12f0jfw{color:#ff3e00}.App-logo.svelte-12f0jfw{height:40vmin;pointer-events:none;margin-bottom:1.0rem;animation:svelte-12f0jfw-App-logo-spin infinite 1.6s ease-in-out alternate}@keyframes svelte-12f0jfw-App-logo-spin{from{transform:scale(1)}to{transform:scale(1.06)}}/*# sourceMappingURL=App.css.map */
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSS source maps! 🎉

@@ -0,0 +1 @@
{"version":3,"names":[],"sources":["App.svelte"],"sourcesContent":["<script lang=\"ts\">\"use strict\";\nlet message = 'Learn Svelte with Typescript';\n</script>\n\n<style>\n:global(body) {\n\tmargin: 0;\n\tfont-family: Arial, Helvetica, sans-serif;\n}\n.App {\n\ttext-align: center;\n}\n.App-header {\n\tbackground-color: #F9F6F6;\n\tcolor: #333;\n\tmin-height: 100vh;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: center;\n\tjustify-content: center;\n\tfont-size: calc(10px + 2vmin);\n}\n.App-link {\n\tcolor: #ff3e00;\n}\n.App-logo {\n\theight: 40vmin;\n\tpointer-events: none;\n\tmargin-bottom: 1.0rem;\n\tanimation: App-logo-spin infinite 1.6s ease-in-out alternate;\n}\n@keyframes App-logo-spin {\n\tfrom {\n\t\ttransform: scale(1);\n\t}\n\tto {\n\t\ttransform: scale(1.06);\n\t}\n}\n</style>\n\n<div class=\"App\">\n\t<header class=\"App-header\">\n\t\t<img src=\"/logo.svg\" class=\"App-logo\" alt=\"logo\" />\n\t\t<p>\n\t\t\tEdit <code>src/App.svelte</code> and save to reload.\n\t\t</p>\n\t\t<a\n\t\t\tclass=\"App-link\"\n\t\t\thref=\"https://svelte.dev\"\n\t\t\ttarget=\"_blank\"\n\t\t\trel=\"noopener noreferrer\"\n\t\t>\n\t\t\t{message}\n\t\t</a>\n\t</header>\n</div>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBAqDI,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IApDP,OAAO,GAAG,8BAA8B;;;CAD1B,YAAY;;;;;;;;;;;"}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JS source maps! 🎉

@@ -0,0 +1 @@
{"version":3,"sources":["/Users/drew/Sites/pikapkg/snowpack/packages/@snowpack/app-template-vue/src/App.vue"],"names":["message"],"mappings":";;qBACO,KAAK,EAAC,KAAK;qBACN,KAAK,EAAC,YAAY;gCACxB,aAAmD;EAA9C,GAAG,EAAC,WAAW;EAAC,KAAK,EAAC,UAAU;EAAC,GAAG,EAAC,MAAM;;gCAChD,aAGI;eAPV,iBAIS,QAED;eAAA,aAAwB,cAAlB,aAAW;eANzB,iBAMgC,uBAC1B;;;EAEE,KAAK,EAAC,UAAU;EAChB,IAAI,EAAC,mBAAmB;EACxB,MAAM,EAAC,QAAQ;EACf,GAAG,EAAC,qBAAqB;;;;wBAX/B,aAcM,OAdN,UAcM;IAbJ,aAYS,UAZT,UAYS;MAXP,UAAmD;MACnD,UAGI;MACJ,aAKkB,KALlB,UAKkB,mBAAdA,YAAO","sourcesContent":["\n <div class=\"App\">\n <header class=\"App-header\">\n <img src=\"/logo.svg\" class=\"App-logo\" alt=\"logo\" />\n <p>\n Edit\n <code>src/App.vue</code> and save to reload.\n </p>\n <a\n class=\"App-link\"\n href=\"https://vuejs.org\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >{{ message }}</a>\n </header>\n </div>\n"]}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vue, too! 🎉

All plugin `options` are passed directly to the Svelte compiler. See [here](https://svelte.dev/docs#svelte_compile) for a list of supported options.
| Name | Type | Description |
| :----------- | :-------: | :---------------------------------------------------------------- |
| `sourceMaps` | `boolean` | Set to `false` to disable source map generation (default: `true`) |
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Svelte + Vue plugins now manage source maps themselves, you can now disable source maps in individual plugins if desired (they’re on by default)

docs/docs/05-configuration.md Show resolved Hide resolved
result[ext + '.map'] =
typeof output.map === 'object' ? JSON.stringify(output.map) : output.map;

const sourceMapFile = path
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we turn this into a helper, something like replaceFileExtension?

Also, see https://nodejs.org/api/path.html#path_path_basename_path_ext for a cleaner way to strip the extension

packages/snowpack/src/build/build-pipeline.ts Outdated Show resolved Hide resolved
packages/snowpack/src/commands/build.ts Outdated Show resolved Hide resolved
allFilesToResolveImports[outLoc] = {baseExt, expandedExt, contents, locOnDisk};
break;

for (const [fileExt, buildResult] of Object.entries(builtFileOutput)) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah good catch! Yup, I bet we just grabbed our old logic here without updating it to the new build map format. This should be good to merge, I can't think of what it could be breaking that isn't already broken

packages/snowpack/src/commands/build.ts Show resolved Hide resolved
packages/snowpack/src/commands/dev.ts Outdated Show resolved Hide resolved
packages/snowpack/src/build/build-pipeline.ts Outdated Show resolved Hide resolved
});
hmrEngine.setEntry(originalReqPath, resolvedImports, isHmrEnabled);

// transform other files
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little bit of unplanned refactoring, but I had such a tough time finding this code block because it looked different from build.ts. Used a switch statement to organize the file transformations a bit better, and tried to start separating “meta” files (.proxy.js, `.map) from other non-meta files.

Copy link
Owner

@FredKSchott FredKSchott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! With one comment about only writing sourceMap if the option is true.

filename: filePath,
});

if (!js) return;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not for this PR but related to the logging PR: it would be great to take a pass at our plugins and logging when things like this happen (I think think would be always unexpected).


switch (fileExt) {
case '.css': {
if (map) code = cssSourceMappingURL(code, sourceMappingURL);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and others: if sourceMap === false, I wouldn't expect any source maps even if the plugin returned one.

This would simplify things for plugin authors as well, where they can always return map if they'd like and then let Snowpack handle whether it gets written or not. Esp. for plugins like Svelte where the map is always returned.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me handle that in the build file step, then, that way it’s only in one place.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in build-pipeline.ts

return generateCssImportProxy({code, hmr, isDev, config});
// if proxying a CSS file, remove its source map (the path no longer applies)
const sanitized = code.replace(/\/\*#\s*sourceMappingURL=[^/]+\//gm, '');
return expandedExt.endsWith('.module.css')
Copy link
Collaborator Author

@drwpow drwpow Aug 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The more I wrestle with this, the more I start to agree with @FredKSchott where we toss out the idea I tried to introduce of a baseExt (.css) and expandedExt (.module.css). It’s hard knowing where to start. I think going forward I’d like to keep it simple, and always assume we want only the final extension. And handle compound extensions (.module.css, .proxy.js, .js.map) on a case-by-case basis. (edit: internally, I mean. Obviously plugins can handle this already with the resolve.* mapping)

@drwpow drwpow merged commit c9348d4 into master Aug 5, 2020
@drwpow drwpow deleted the drwpow/source-maps branch August 5, 2020 00:39
@drwpow drwpow mentioned this pull request Aug 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants