nano-css icon indicating copy to clipboard operation
nano-css copied to clipboard

Source maps

Open elektronik2k5 opened this issue 7 years ago • 4 comments

Hi @streamich,

Awesome and thorough work on this! :) I believe css-in-js is the future and am always glad to see new and ambitious projects. I also like how everything is optional, pluggable and that nothing is opinionated and that it is framework/runtime agnostic.

I realize it's a new project and probably still lacks some features, and I bet you've got a list of these too :). One thing which I personally, can't live without in css-in-js (and JS transpilers) is source maps. In the world of css-in-js, I've only used styled-components and emotion so far. The latter supports source maps, while the former doesn't. To me, it is such a detrimental feature that I may switch from styled to emotion in a large project I lead.

Hope you add source maps to nano-css at some point. I'll be keeping an eye on your project, since it seems promising.

elektronik2k5 avatar Apr 11 '18 13:04 elektronik2k5

@elektronik2k5 what do you think about having devtools for CSS, like a panel in Kuker?

https://github.com/krasimir/kuker/issues/6

streamich avatar Apr 11 '18 13:04 streamich

Thanks for introducing me to Kuker.

In my view, it is an interesting tool, but by no means a replacement for source maps. Source maps "just work" in all modern browsers, while Kuker requires both app runtime and an extension. That is a very high barrier to entry - just to inspect styles.

They can be complementary tools though.

elektronik2k5 avatar Apr 11 '18 15:04 elektronik2k5

Example source map implementation:

  • https://github.com/rtsao/styletron/pull/231
/* eslint-env browser */

import StackTrace from "stacktrace-js";
import {encode} from "sourcemap-codec";

const cache = {};

const schedule = window.requestIdleCallback
  ? task => window.requestIdleCallback(task, {timeout: 180})
  : window.requestAnimationFrame;

let counter = 0;
let queue = [];
let debugEnabled = false;

export function enableDebug() {
  debugEnabled = true;
}

export function addDebugClass(baseStyletron, stackIndex) {
  if (!debugEnabled) {
    return;
  }
  const {className, selector} = getUniqueId();
  baseStyletron.debugClass = className;

  const trace = getTrace();

  trace
    .then(stackframes => {
      const {fileName, lineNumber} = stackframes[stackIndex];
      addToQueue({selector, lineNumber, fileName});
    })
    .catch(err => console.log(err)); // eslint-disable-line no-console
}

function flush() {
  const {rules, segments, sources} = queue.reduce(
    (acc, {selector, lineNumber, fileName}) => {
      let sourceIndex = acc.sources.indexOf(fileName);
      if (sourceIndex === -1) {
        sourceIndex = acc.sources.push(fileName) - 1;
      }
      acc.rules.push(`${selector} {}`);
      acc.segments.push([[0, sourceIndex, lineNumber - 1, 0]]);
      return acc;
    },
    {rules: [], segments: [], sources: []},
  );
  queue = [];

  const mappings = encode(segments);
  const map = {
    version: 3,
    sources,
    mappings,
    sourcesContent: sources.map(source => cache[source]),
  };

  const json = JSON.stringify(map);
  const base64 = window.btoa(json);

  const css =
    rules.join("\n") +
    `\n\/*# sourceMappingURL=data:application/json;charset=utf-8;base64,${base64} */`;
  const style = document.createElement("style");
  style.appendChild(document.createTextNode(css));
  document.head.appendChild(style);
}

function addToQueue(item) {
  const prevCount = queue.length;
  queue.push(item);
  if (prevCount === 0) {
    schedule(flush);
  }
}

function getTrace() {
  return StackTrace.get({sourceCache: cache});
}

function getUniqueId() {
  const id = counter++;
  const className = `__debug_${id}`;
  return {
    selector: `.${className}`,
    className,
  };
}

streamich avatar May 01 '18 23:05 streamich

Add sourcemaps addon: https://github.com/streamich/nano-css/blob/master/docs/sourcemaps.md

Tell me if it works for you!

streamich avatar Jul 11 '18 00:07 streamich