Skip to content

Commit 4783c43

Browse files
authored
Compile styles using shared worker thread (giuseppeg#49)
1 parent 63bd1e1 commit 4783c43

File tree

18 files changed

+309
-146
lines changed

18 files changed

+309
-146
lines changed

.github/workflows/node.js.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ jobs:
2525
uses: actions/setup-node@v1
2626
with:
2727
node-version: ${{ matrix.node-version }}
28-
- run: npm ci
29-
- run: npm test
28+
- run: yarn install --frozen-lockfile
29+
- run: yarn test

.npmignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
postcss.config.js
22
test.js
3-
fixture.css
3+
fixtures

.travis.yml

Lines changed: 0 additions & 5 deletions
This file was deleted.

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ Use [PostCSS](https://github.com/postcss/postcss) with
88

99
⚠️ **This plugin is not actively being maintained. If you want me to work on it please [consider donating](https://github.com/sponsors/giuseppeg).**
1010

11+
## Supporters
12+
13+
Companies and individuals who sponsored some work on this library:
14+
15+
🥇 [@swissredcross](https://github.com/swissredcross)
16+
1117
## Usage
1218

1319
Install this package first.
@@ -39,7 +45,8 @@ With config:
3945
[
4046
"styled-jsx-plugin-postcss",
4147
{
42-
"path": "[PATH_PREFIX]/postcss.config.js"
48+
"path": "[PATH_PREFIX]/postcss.config.js",
49+
"compileEnv": "worker"
4350
}
4451
]
4552
]
@@ -49,6 +56,12 @@ With config:
4956
}
5057
```
5158

59+
## compileEnv
60+
61+
When using Node.js v12.3.0 and above the plugin defaults to compiling using a worker thread instead of a child process. This results in faster builds.
62+
63+
If for any reason you want to force compiling using a child process (slower) you can register the plugin with the config option `compileEnv` set to `process`.
64+
5265
### Example with CRA
5366

5467
Usage with Create React App requires you to either _eject_ or use [react-app-rewired](https://github.com/timarney/react-app-rewired).

compile.js

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
const { spawnSync } = require("child_process");
2+
const path = require("path");
3+
const {
4+
Worker,
5+
receiveMessageOnPort,
6+
MessageChannel,
7+
} = require("worker_threads");
8+
const error = require("./error");
9+
10+
let worker = null;
11+
let unreftimeout = null;
12+
13+
function compileWorker(...args) {
14+
if (unreftimeout) {
15+
clearTimeout(unreftimeout);
16+
unreftimeout = null;
17+
}
18+
19+
if (!worker) {
20+
worker = new Worker(require.resolve("./worker.js"));
21+
}
22+
23+
const signal = new Int32Array(new SharedArrayBuffer(4));
24+
signal[0] = 0;
25+
26+
try {
27+
const subChannel = new MessageChannel();
28+
worker.postMessage({ signal, port: subChannel.port1, args }, [
29+
subChannel.port1,
30+
]);
31+
32+
const workStartedAt = Date.now();
33+
const settings = args[1] || {};
34+
const LOCK_TIMEOUT = settings.lockTimeout || 10000;
35+
Atomics.wait(signal, 0, 0, LOCK_TIMEOUT);
36+
37+
const result = receiveMessageOnPort(subChannel.port2);
38+
39+
if (!result) {
40+
if (Date.now() - workStartedAt >= LOCK_TIMEOUT) {
41+
error(
42+
`postcss is taking more than ${LOCK_TIMEOUT /
43+
1000}s to compile the following styles:\n\n` +
44+
`Filename: ${(settings.babel || {}).filename ||
45+
"unknown filename"}\n\n` +
46+
args[0]
47+
);
48+
}
49+
error(`postcss' compilation result is undefined`);
50+
}
51+
const { message } = result;
52+
if (message.error) {
53+
error(`postcss failed with ${message.error}`);
54+
}
55+
return message.result;
56+
} catch (error) {
57+
throw error;
58+
} finally {
59+
unreftimeout = setTimeout(() => {
60+
worker.unref();
61+
worker = null;
62+
unreftimeout = null;
63+
}, 1000);
64+
}
65+
}
66+
67+
function compileSubprocess(css, settings) {
68+
const result = spawnSync("node", [path.resolve(__dirname, "subprocess.js")], {
69+
input: JSON.stringify({
70+
css,
71+
settings,
72+
}),
73+
encoding: "utf8",
74+
});
75+
76+
if (result.status !== 0) {
77+
if (result.stderr.includes("Invalid PostCSS Plugin")) {
78+
let isNext = false;
79+
try {
80+
require.resolve("next");
81+
isNext = true;
82+
} catch (err) {}
83+
if (isNext) {
84+
console.error(
85+
"Next.js 9 default postcss support uses a non standard postcss config schema https://err.sh/next.js/postcss-shape, you must use the interoperable object-based format instead https://nextjs.org/docs/advanced-features/customizing-postcss-config"
86+
);
87+
}
88+
}
89+
90+
error(`postcss failed with ${result.stderr}`);
91+
}
92+
93+
return result.stdout;
94+
}
95+
96+
module.exports = (css, settings) => {
97+
if (
98+
typeof receiveMessageOnPort === "undefined" ||
99+
settings.compileEnv === "process"
100+
) {
101+
return compileSubprocess(css, settings);
102+
} else {
103+
return compileWorker(css, settings);
104+
}
105+
};

error.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = function error(message) {
2+
throw new Error(`[styled-jsx-plugin-postcss] ${message}`);
3+
};

fixture-postcss-plugin.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

fixtures/fixture-postcss-plugin.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const postcss = require("postcss");
2+
3+
module.exports = (options = {}) => ({
4+
postcssPlugin: "postcss-csso",
5+
Rule(rule, { result, postcss }) {
6+
rule.selector = rule.selector
7+
.split(" ")
8+
.map((s) => `${s}.plugin`)
9+
.join(" ");
10+
return rule;
11+
},
12+
});
13+
14+
module.exports.postcss = true;
File renamed without changes.

0 commit comments

Comments
 (0)