Comments (2)
I had this same problem and solved it a slightly different way.
I injected a custom source file loader into the postcss-modules options in my rollup config, using the Loader
option.
The custom Loader is based on the FileSystemLoader found in css-modules-loader-core: https://github.com/css-modules/css-modules-loader-core/blob/master/src/file-system-loader.js
But instead of using Node's fs
to read files, it uses node-sass
to read files and render them with Sass during the composition process.
I think this way is less hacky, and doesn't require any extra temporary files. I don't like that I have to copy the FileSystemLoader completely, but a comment at the top makes it more apparent why I've copied it.
Here is my rollup.config.js and my custom loader.
// Abbreviated rollup.config.js
import path from 'path'
import sass from 'node-sass'
import postcss from 'rollup-plugin-postcss'
import postcssModules from 'postcss-modules'
import autoprefixer from 'autoprefixer'
import CssModulesSassLoader from './CssModulesSassLoader'
const cssExportMap = {}
const sassPreprocessor = (content, id) => new Promise((resolve) => {
const result = sass.renderSync({ file: id })
resolve({ code: result.css.toString() })
})
export default {
... other rollup config ...
plugins: [
... other plugins ...
postcss({
extract: path.resolve('./dist/components.css'),
sourceMap: true,
extensions: ['.scss'],
preprocessor: sassPreprocessor, // Pre-process all imports with Sass
plugins: [
autoprefixer(),
postcssModules({
Loader: CssModulesSassLoader, // Load all "composes" files with Sass
generateScopedName: '[name]__[local]___[hash:base64:5]',
getJSON(id, exportTokens) {
cssExportMap[id] = exportTokens
}
})
],
getExportNamed: false,
getExport(id) {
return cssExportMap[id]
}
})
]
}
// CssModulesSassLoader.js
/**
* This is a copy of the FileSystemLoader from https://github.com/css-modules/css-modules-loader-core/blob/master/src/file-system-loader.js
* with one key difference. Instead of loading files using Node's built-int file system module (`fs`), it loads files
* with Sass. This allows us to use Sass with CSS Modules `composes`:
*
* .someClass {
* composes: otherClass from '../Other/Other.scss'
* }
*
* The original loading code with `fs` is commented out starting on line 70, and is replaced with `sass.render` on line 81.
* **There are no other modifications.**
*
*
*/
import path from 'path'
import Core from 'css-modules-loader-core'
import sass from 'node-sass'
// Sorts dependencies in the following way:
// AAA comes before AA and A
// AB comes after AA and before A
// All Bs come after all As
// This ensures that the files are always returned in the following order:
// - In the order they were required, except
// - After all their dependencies
const traceKeySorter = (a, b) => {
if (a.length < b.length) {
return a < b.substring(0, a.length) ? -1 : 1
} else if (a.length > b.length) {
return a.substring(0, b.length) <= b ? -1 : 1
} else {
return a < b ? -1 : 1
}
}
export default class CssModulesSassLoader {
constructor(root, plugins) {
this.root = root
this.sources = {}
this.traces = {}
this.importNr = 0
this.core = new Core(plugins)
this.tokensByFile = {}
}
fetch(_newPath, relativeTo, _trace) {
let newPath = _newPath.replace(/^["']|["']$/g, ''),
trace = _trace || String.fromCharCode(this.importNr++)
return new Promise((resolve, reject) => {
let relativeDir = path.dirname(relativeTo),
rootRelativePath = path.resolve(relativeDir, newPath),
fileRelativePath = path.resolve(path.join(this.root, relativeDir), newPath)
// if the path is not relative or absolute, try to resolve it in node_modules
if (newPath[0] !== '.' && newPath[0] !== '/') {
try {
fileRelativePath = require.resolve(newPath)
}
catch (e) {
}
}
const tokens = this.tokensByFile[fileRelativePath]
if (tokens) {
return resolve(tokens)
}
// fs.readFile( fileRelativePath, "utf-8", ( err, source ) => {
// if ( err ) reject( err )
// this.core.load( source, rootRelativePath, trace, this.fetch.bind( this ) )
// .then( ( { injectableSource, exportTokens } ) => {
// this.sources[fileRelativePath] = injectableSource
// this.traces[trace] = fileRelativePath
// this.tokensByFile[fileRelativePath] = exportTokens
// resolve( exportTokens )
// }, reject )
// } )
sass.render({ file: fileRelativePath }, (err, source) => {
if (err) reject(err)
this.core.load(source.css.toString(), rootRelativePath, trace, this.fetch.bind(this))
.then(({ injectableSource, exportTokens }) => {
this.sources[fileRelativePath] = injectableSource
this.traces[trace] = fileRelativePath
this.tokensByFile[fileRelativePath] = exportTokens
resolve(exportTokens)
}, reject)
})
})
}
get finalSource() {
const traces = this.traces
const sources = this.sources
let written = new Set()
return Object.keys(traces).sort(traceKeySorter).map(key => {
const filename = traces[key]
if (written.has(filename)) {
return null
}
written.add(filename)
return sources[filename]
}).join('')
}
}
from rollup-plugin-postcss.
I guess this is not a problem anymore, feel free to re-open if it still doesn't work.
from rollup-plugin-postcss.
Related Issues (20)
- postcss/lib/processor.es6:139:15
- Not working with scss modules including inline comments
- React npm packages using rollup not working with srr or nextjs? HOT 5
- Usage of "~" sign in imports
- [scss] Sources path in extracted "*.map.css" file is not correct - hierarchy of folders is missed. HOT 1
- Error thrown "@use rules must be written before any other rules." HOT 1
- No option to generate moduler css along with one single css which will load separately into dom
- Question: Is there a way to add attributes to the <style> tag generated? HOT 1
- Customize `less` instance
- Is it possible to set stylesheet order?
- On watch mode generated CSS sometimes is prepended when using multiple CSS files
- Sourcemap file points to the compiled scss when its setting is `true`
- Bundle webcomponent.js with webcomponent.css
- 编译css文件失败 HOT 3
- How to use only dart(sass) without node-sass
- Nextjs support: The server side rendering of components is making it unstyled. HOT 3
- Can't use mjs config files HOT 2
- Move to `postcss-load-config` 5.0
- Cannot convert deep syntax in Vue HOT 2
- ES module support
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rollup-plugin-postcss.