Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
name: Node.js CI
on:
push:
branches: [v3, v4]
pull_request:
branches: [v3, v4]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x, 16.x, 18.x, 19.x]
node-version: [16.x, 18.x, 19.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ node_modules
# Build files
dist
/test/**/output.*
/test/**/output/
17 changes: 12 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"name": "rollup-plugin-css-only",
"name": "@sgratzl/rollup-plugin-css-only",
"publishConfig": {
"access": "public"
},
"version": "4.3.0",
"description": "Rollup plugin that bundles imported css",
"main": "dist/index.cjs",
Expand All @@ -18,8 +21,9 @@
"test:nested": "cd test/nested && rm -rf output && rollup -c && cmp output/output.js expected.js && cmp output/output.css expected.css && cd ../..",
"test:empty": "cd test/empty && rm -rf output && rollup -c && cmp output/output.js expected.js && cmp output/output.css expected.css && cd ../..",
"test:simple": "cd test/simple && rm -rf output && rollup -c && cmp output/output.js expected.js && cmp output/output.css expected.css && cd ../..",
"test:imports": "cd test/imports && rm -rf output && rollup -c && cmp output/output.js expected.js && cmp output/output.css expected.css && cd ../..",
"test:win:simple": "cd .\\test\\simple && del -f output.* && rollup -c && cd .. && ECHO n|comp simple\\output.js expected.js && ECHO n|comp simple\\output.css simple\\expected.css && cd ..",
"test": "npm run test:simple && npm run test:nested && npm run test:empty && npm run test:circular",
"test": "npm run test:simple && npm run test:nested && npm run test:empty && npm run test:circular && npm run test:imports",
"test:win": "npm run test:win:simple",
"lint": "prettier rollup.config.js src/**",
"prepare": "npm run build",
Expand All @@ -34,13 +38,16 @@
],
"license": "MIT",
"author": "Thomas Ghysels <[email protected]>",
"homepage": "https://github.com/thgh/rollup-plugin-css-only",
"contributors": [
"Samuel Gratzl <[email protected]>"
],
"homepage": "https://github.com/sgratzl/rollup-plugin-css-only",
"bugs": {
"url": "https://github.com/thgh/rollup-plugin-css-only/issues"
"url": "https://github.com/sgratzl/rollup-plugin-css-only/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/thgh/rollup-plugin-css-only"
"url": "https://github.com/sgratzl/rollup-plugin-css-only"
},
"files": [
"dist"
Expand Down
87 changes: 60 additions & 27 deletions src/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,38 @@ export default function css(options = {}) {
let fileName = options.fileName

// Get all CSS modules in the order that they were imported
const getCSSModules = (id, getModuleInfo, modules = new Set(), visitedModules = new Set()) => {
if (modules.has(id) || visitedModules.has(id)) {
return new Set()
const getCSSModules = (id, getModuleInfo) => {
const modules = [];
const visited = new Set();

// traversal logic
// 1. mark node as visited
// 2. add to list at the end
// 3. go down with imports but in reverse order
// 4. reverse full list
// example
// root
// 1
// 11
// 12
// 2
// 21
// 22
// will result in the list: root, 2, 22, 21, 1, 12, 11
// revered: 11, 12, 1, 21, 22, 2, root
const visitModule = (id) => {
if (visited.has(id)) {
return;
}
visited.add(id);
if (filter(id)) {
modules.push(id);
}
const reverseChildren = getModuleInfo(id).importedIds.slice().reverse();
reverseChildren.forEach(visitModule);
}

if (filter(id)) modules.add(id)

// Prevent infinite recursion with circular dependencies
visitedModules.add(id);

// Recursively retrieve all of imported CSS modules
const info = getModuleInfo(id)
if (!info) return modules

info.importedIds.forEach(importId => {
modules = new Set(
[].concat(
Array.from(modules),
Array.from(getCSSModules(importId, getModuleInfo, modules, visitedModules))
)
)
})

return modules
visitModule(id);
return modules.reverse();
}

return {
Expand All @@ -41,22 +49,34 @@ export default function css(options = {}) {
return
}

const { imports, codeWithoutImports } = splitImports(code);

// When output is disabled, the stylesheet is exported as a string
if (options.output === false) {
if (imports.length === 0) {
return {
code: `export default ${JSON.stringify(code)}`,
map: { mappings: '' }
}
}
const importNamed = imports.map((d, i) => `import i${i} from ${d}`).join('\n');
return {
code: 'export default ' + JSON.stringify(code),
code: `
${importNamed}
export default ${imports.map((_, i) => `i${i}`).join(' + ')} + ${JSON.stringify(codeWithoutImports)}`,
map: { mappings: '' }
}
}

// Keep track of every stylesheet
// Check if it changed since last render
// NOTE: If we are in transform block, we can assume styles[id] !== code, right?
if (styles[id] !== code && (styles[id] || code)) {
styles[id] = code
if (styles[id] !== codeWithoutImports && (styles[id] || codeWithoutImports)) {
styles[id] = codeWithoutImports
}

return ''
// return a list of imports
return imports.map((d) => `import ${d}`).join('\n');
},
generateBundle(opts, bundle) {
const ids = []
Expand Down Expand Up @@ -86,3 +106,16 @@ export default function css(options = {}) {
}
}
}


function splitImports(code) {
const imports = [];
const codeWithoutImports = code.replace(/@import\s+(.*);[\r\n]*/gm, (_, group) => {
imports.push(group.replace(/(["'])~/, '$1'));
return '';
});
return {
imports,
codeWithoutImports
};
}
2 changes: 1 addition & 1 deletion test/circular/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import css from 'rollup-plugin-css-only'
import css from '../../src/index.mjs'

export default {
input: 'a.js',
Expand Down
3 changes: 3 additions & 0 deletions test/imports/css/first.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.first {
color: blue;
}
5 changes: 5 additions & 0 deletions test/imports/css/input.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import './second.css';

.last {
color: green;
}
5 changes: 5 additions & 0 deletions test/imports/css/second.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import './first.css';

.second {
color: green;
}
12 changes: 12 additions & 0 deletions test/imports/expected.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.first {
color: blue;
}

.second {
color: green;
}

.last {
color: green;
}

1 change: 1 addition & 0 deletions test/imports/expected.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('css imported');
3 changes: 3 additions & 0 deletions test/imports/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import './css/input.css'

console.log('css imported')
12 changes: 12 additions & 0 deletions test/imports/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import css from '../../src/index.mjs'

export default {
input: 'input.js',
output: {
file: 'output/output.js',
format: 'esm'
},
plugins: [
css({ output: 'output.css' })
]
}