asyncLiz / minify-html-literals

Minify HTML template literal strings
MIT License
68 stars 13 forks source link

Please add support for newly added css literal in lit-element #3

Closed motss closed 5 years ago

motss commented 5 years ago

See Polymer/lit-element#391 for more info.

// In latest version, we can now use `css` literal for styling.
...
statc get styles() {
  return [
    css`:host { display: block; }`,
  ];
}
...
asyncLiz commented 5 years ago

I'll need to add support to detect and minify just CSS text. I can also go ahead and add some more default detection other than the html tag, being able to specify a comment before a template literal string would be super useful.

I run into this a lot when adding <custom-style> markup for Polymer/Vaadin theming, and we use a vscode plugin that formats the html when it sees the comment.

element.innerHTML = /*html*/`
  <custom-style>
    ...
  </custom-style>
`;
motss commented 5 years ago

Great to hear that this is a confirmed issue.

Worth to note that there is a problem with the said plugin es6-string-html is that it does not support commenting on different languages really well. When you try Ctrl + / (on Windows or Linux) or Cmd + / (for Macs).

It would be great to see the language type via comment for string literals lands on next release.

Dabolus commented 5 years ago

+1, this would be useful not only for lit-element, but also for native JavaScript, since it is now possible to build a CSS stylesheet using JS (proposal). For example, on Chrome Canary you can already do something like this:

// Construct the CSSStyleSheet
const stylesheet = new CSSStyleSheet();

// Add some CSS
stylesheet.replaceSync(/* css */`
  body {
    background: #000 !important;
  }
`);
// OR stylesheet.replace, which returns a Promise instead

// Tell the document to adopt your new stylesheet.
// Note that this also works with Shadow Roots.
document.adoptedStyleSheets = [stylesheet];
asyncLiz commented 5 years ago

At the moment I'm thinking of rewriting this to be a little more generic. After all, it uses parse-literals, which doesn't care about the content of the literal, so there's no reason it can't be expanded to perform post-processing tasks on ANY literal string.

Whether it's HTML, CSS, JS, markdown, or some other content that you want to post process (not just limited to minifying), you could use a single plugin to do that work. Sort of like PostCSS.

This is my current idea:

const result = processLiterals(code, [
  // An array of processors. They will need a way to check if they should process a
  // literal, then a function to perform the transformation
  {
    prefix: /html(\s*\*\/)?`/,
    process(literal) {
      const ms = new MagicString(literal.text);
      minifyHTML(ms);
      return { code: ms.toString(), map: ms.generateMap(); };
    }
  },
  {
    prefix: /css(\s*\*\/)?`/,
    process(literal) {
      const ms = new MagicString(literal.text);
      minifyCSS(ms);
      return { code: ms.toString(), map: ms.generateMap(); };
    }
  }
]);

Individual processors could have builders as well to take options and make the dev UX easier. The module could ship with some common plugins for things like minifying.

import { processLiterals, minifyHTML, minifyCSS } from 'minify-html-literals';
import { customLiteralPostProcessor } from './custom-processor';

const result = processLiterals(code, [
  minifyHTML({ /* html-minifier options */ }),
  minifyCSS({ /* clean-css options */ }),
  customLiteralPostProcessor()
]);

This would allow devs complete control over what is happening when they post process literals at build time. It would also give us an environment to add plugins and be more flexible and future-proof for whatever the JS community uses template literal strings for.

What do you guys think? Feedback is appreciated!

motss commented 5 years ago

This looks good to me. Looks like a better approach to tackle all the different types of content. It should be extensible by the devs if they wanted to, right?

On Thu, Jan 17, 2019, 10:09 AM Liz Mitchell notifications@github.com wrote:

At the moment I'm thinking of rewriting this to be a little more generic. After all, it uses parse-literals https://github.com/asyncLiz/parse-literals, which doesn't care about the content of the literal, so there's no reason it can't be expanded to perform post-processing tasks on ANY literal string.

Whether it's HTML, CSS, JS, markdown, or some other content that you want to post process (not just limited to minifying), you could use a single plugin to do that work. Sort of like PostCSS.

This is my current idea:

const result = processLiterals(code, [ // An array of processors. They will need a way to check if they should process a // literal, then a function to perform the transformation { prefix: /html(\s*\/)?`/, process(literal) { const ms = new MagicString(literal.text); minifyHTML(ms); return { code: ms.toString(), map: ms.generateMap(); }; } }, { prefix: /css(\s*\/)?`/, process(literal) { const ms = new MagicString(literal.text); minifyCSS(ms); return { code: ms.toString(), map: ms.generateMap(); }; } } ]);

Individual processors could have builders as well to take options and make the dev UX easier. The module could ship with some common plugins for things like minifying.

import { processLiterals, minifyHTML, minifyCSS } from 'minify-html-literals';import { customLiteralPostProcessor } from './custom-processor'; const result = processLiterals(code, [ minifyHTML({ / html-minifier options / }), minifyCSS({ / clean-css options / }), customLiteralPostProcessor() ]);

This would allow devs complete control over what is happening when they post process literals at build time. It would also give us an environment to add plugins and be more flexible and future-proof for whatever the JS community uses template literal strings for.

What do you guys think? Feedback is appreciated!

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/asyncLiz/minify-html-literals/issues/3#issuecomment-455015630, or mute the thread https://github.com/notifications/unsubscribe-auth/AKHcj06EpQxvZ4pM6TbPYo9P9k5PrAk_ks5vD9tugaJpZM4Z8uSS .

Dabolus commented 5 years ago

Totally love this, it would become an incredibly powerful tool!

@motss yes, taking the example given by @asyncLiz you are able to write your own processor for some type of literal and even share it on npm. And the awesome thing is that you can actually use it to do more than just minifying. A small example:

my-scss-minifier

export const compileAndMinifySCSS = (options) => ({
  prefix: options.prefix || /\/\* scss \*\//,
  process(literal) {
    const ms = new MagicString(literal.text);
    compileSCSS(ms);
    minifyCSS(ms);
    return { code: ms.toString(); map: ms.generateMap(); };
  }
});

So that now you can do:

import { processLiterals, minifyHTML } from 'minify-html-literals';
import { compileAndMinifySCSS } from 'my-scss-minifier';

const result = processLiterals(code, [
  minifyHTML(),
  compileAndMinifySCSS()
]);
motss commented 5 years ago

@Dabolus Thanks for the further explanation to clear the doubts. In that case, it looks really promising.

👍 for the new approach.

stramel commented 5 years ago

:+1: for the new API direction. I could see it being useful for adding an SVG minifier in as well since lit-html has a SVG tag too.

asyncLiz commented 5 years ago

I've decided to go ahead and add capabilities to minify css templates in this package since it's taking me too long to work on the new API.

I'm still going to start the new API, but I'm going to separate it into a completely new project that will eventually replace this one.