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

Option to output CSS instead of JS #185

Open
bennypowers opened this issue Aug 5, 2019 · 6 comments
Open

Option to output CSS instead of JS #185

bennypowers opened this issue Aug 5, 2019 · 6 comments

Comments

@bennypowers
Copy link

👋 Hello! Thanks for publishing this useful package 😄

I'm the author of another CSS plugin for rollup, rollup-plugin-lit-css, which is a simple plugin for importing css files into javascript as lit-element css tagged template literals.

I'd like for my users to have the option to pass their CSS through postcss before loading into JS, and have the postcss rollup plugin output a string of CSS without adding js syntax.

Input

app.js

import style from './styles.css'
console.log(style)

styles.css

main {
  background: red;
  &.nested { background: blue; }
}

rollup.config.js

import postcss from 'rollup-plugin-postcss'
import litcss from 'rollup-plugin-lit-css'

export default {
  input: 'app.js',
  output: {
    format: 'es',
    file: 'bundle.js',
  },
  plugins: [
    postcss({
      output: 'css',
      inject: false,
      plugins: [
        require('postcss-preset-env')({stage: 0})
      ]
    }),
    litcss(),
  ],
}

Expected bundle.js

import { css } from 'lit-element';

var style = css`main {
  background: red
}
main.nested { background: blue; }
`;

console.log(style);

Actual bundle.js

import { css } from 'lit-element';

var style = css`var css = "main {\n  background: red\n}\nmain.nested { background: blue; }\n";
export default css;`;

console.log(style);

If this option is already available, I wasn't able to find it in the docs or the source. From a brief tour of the source, it looks like the plugin always exports JS.

Thanks again for publishing this.

@himself65
Copy link
Collaborator

we need to refactor this function

async process({ code, map }) {
const config = this.options.config ?
await loadConfig(this.id, this.options.config) :
{}
const options = this.options
const plugins = [
...(options.postcss.plugins || []),
...(config.plugins || [])
]
const shouldExtract = options.extract
const shouldInject = options.inject
const modulesExported = {}
const autoModules = options.autoModules !== false && isModuleFile(this.id)
const supportModules = options.modules || autoModules
if (supportModules) {
plugins.push(
require('postcss-modules')({
// In tests
// Skip hash in names since css content on windows and linux would differ because of `new line` (\r?\n)
generateScopedName: process.env.ROLLUP_POSTCSS_TEST ?
'[name]_[local]' :
'[name]_[local]__[hash:base64:5]',
...options.modules,
getJSON(filepath, json, outpath) {
modulesExported[filepath] = json
if (
typeof options.modules === 'object' &&
typeof options.modules.getJSON === 'function'
) {
return options.modules.getJSON(filepath, json, outpath)
}
}
})
)
}
// If shouldExtract, minimize is done after all CSS are extracted to a file
if (!shouldExtract && options.minimize) {
plugins.push(require('cssnano')(options.minimize))
}
const postcssOpts = {
...this.options.postcss,
...config.options,
// Allow overriding `to` for some plugins that are relying on this value
to: options.to || this.id,
// Followings are never modified by user config config
from: this.id,
map: this.sourceMap ?
shouldExtract ?
{ inline: false, annotation: false } :
{ inline: true, annotation: false } :
false
}
delete postcssOpts.plugins
postcssOpts.parser = ensurePostCSSOption(postcssOpts.parser)
postcssOpts.syntax = ensurePostCSSOption(postcssOpts.syntax)
postcssOpts.stringifier = ensurePostCSSOption(postcssOpts.stringifier)
if (map && postcssOpts.map) {
postcssOpts.map.prev = typeof map === 'string' ? JSON.parse(map) : map
}
if (plugins.length === 0) {
// Prevent from postcss warning:
// You did not set any plugins, parser, or stringifier. Right now, PostCSS does nothing. Pick plugins for your case on https://www.postcss.parts/ and use them in postcss.config.js
const noopPlugin = postcss.plugin('postcss-noop-plugin', () => () => {
/* noop */
})
plugins.push(noopPlugin())
}
const res = await postcss(plugins).process(code, postcssOpts)
for (const msg of res.messages) {
if (msg.type === 'dependency') {
this.dependencies.add(msg.file)
}
}
for (const warning of res.warnings()) {
this.warn(warning)
}
const outputMap = res.map && JSON.parse(res.map.toString())
if (outputMap && outputMap.sources) {
outputMap.sources = outputMap.sources.map(v => normalizePath(v))
}
let output = ''
let extracted
if (options.namedExports) {
const json = modulesExported[this.id]
const getClassName =
typeof options.namedExports === 'function' ?
options.namedExports :
ensureClassName
// eslint-disable-next-line guard-for-in
for (const name in json) {
const newName = getClassName(name)
// Log transformed class names
// But skip this when namedExports is a function
// Since a user like you can manually log that if you want
if (name !== newName && typeof options.namedExports !== 'function') {
this.warn(
`Exported "${name}" as "${newName}" in ${humanlizePath(this.id)}`
)
}
if (!json[newName]) {
json[newName] = json[name]
}
output += `export var ${newName} = ${JSON.stringify(json[name])};\n`
}
}
if (shouldExtract) {
output += `export default ${JSON.stringify(modulesExported[this.id])};`
extracted = {
id: this.id,
code: res.css,
map: outputMap
}
} else {
output += `var css = ${JSON.stringify(res.css)};\nexport default ${
supportModules ? JSON.stringify(modulesExported[this.id]) : 'css'
};\nexport const stylesheet=${JSON.stringify(res.css)};`
}
if (!shouldExtract && shouldInject) {
output += `\nimport styleInject from '${styleInjectPath}';\nstyleInject(css${
Object.keys(options.inject).length > 0 ?
`,${JSON.stringify(options.inject)}` :
''
});`
}
return {
code: output,
map: outputMap,
extracted
}
}

@bennypowers
Copy link
Author

So this patch naively accomplishes my goal in OP:

diff --git a/node_modules/rollup-plugin-postcss/dist/index.js b/node_modules/rollup-plugin-postcss/dist/index.js
index 57d9e04..bad0ff4 100644
--- a/node_modules/rollup-plugin-postcss/dist/index.js
+++ b/node_modules/rollup-plugin-postcss/dist/index.js
@@ -307,6 +307,10 @@ var postcssLoader = {
         output += `\nimport styleInject from '${styleInjectPath}';\nstyleInject(css${Object.keys(options.inject).length > 0 ? `,${JSON.stringify(options.inject)}` : ''});`;
       }
 
+      if (options.output === 'css') {
+        output = res.css;
+      }
+
       return {
         code: output,
         map: outputMap,
@@ -682,6 +686,8 @@ var index = ((options = {}) => {
     /** Inject CSS as `<style>` to `<head>` */
     inject: inferOption(options.inject, {}),
 
+    output: options.output || 'js',
+
     /** Extract CSS */
     extract: typeof options.extract === 'undefined' ? false : options.extract,
 

@himself65
Copy link
Collaborator

nice idea, but I'm thinking to use inject: Function to achieve this

related #199

This was referenced Mar 8, 2020
@himself65 himself65 reopened this Mar 8, 2020
@bennypowers
Copy link
Author

acc'd to readme, inject is meant to add a script to index.html containing these javascript objects.

In my case, i'd simply like to transpile the css using post css, so I can import it as a js module using other tools

@bennypowers
Copy link
Author

bennypowers commented Mar 21, 2020

May I suggest a compose: true option which does essentially what my patch above does?

alternatively, would you be willing to accept a PR with output = 'css' as described in that same patch?

@himself65
Copy link
Collaborator

alternatively, would you be willing to accept a PR with output = 'css' as described in that same patch?

sure, I recently have other things to do, so no time to add features for this project

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants