@epublishing/grunt-epublishing 1.2.5 → 1.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/epublishing-grunt-epublishing-1.2.7.tgz +0 -0
- package/lib/cli.js +28 -1
- package/lib/sass-compiler.js +31 -3
- package/package.json +1 -1
|
Binary file
|
package/lib/cli.js
CHANGED
|
@@ -60,10 +60,12 @@ function printOptions(options) {
|
|
|
60
60
|
/**
|
|
61
61
|
* Run npm install in jade and jade child gem directories.
|
|
62
62
|
* Installs packages from each gem's package.json (excluding site).
|
|
63
|
+
* Skips if package-lock.json hasn't changed since the last install.
|
|
63
64
|
* @param {Object} config - Build configuration with paths
|
|
64
65
|
* @param {Object} options - Build options
|
|
65
66
|
*/
|
|
66
67
|
async function runNpmInstall(config, options) {
|
|
68
|
+
const crypto = require('crypto');
|
|
67
69
|
const Resolver = require('@epublishing/jade-resolver');
|
|
68
70
|
const paths = config.paths || {};
|
|
69
71
|
// Build paths object with ONLY jade and jade child gem directories (absolute paths)
|
|
@@ -89,10 +91,25 @@ async function runNpmInstall(config, options) {
|
|
|
89
91
|
|
|
90
92
|
for (const dir of dirs) {
|
|
91
93
|
const basename = path.basename(dir);
|
|
94
|
+
const lockFile = path.join(dir, 'package-lock.json');
|
|
95
|
+
const hasLock = fs.existsSync(lockFile);
|
|
96
|
+
const stampFile = path.join(dir, 'node_modules', '.package-lock.installed');
|
|
97
|
+
|
|
98
|
+
// Skip reinstall if package-lock.json hasn't changed since last npm ci
|
|
99
|
+
if (hasLock && fs.existsSync(stampFile)) {
|
|
100
|
+
const currentHash = crypto.createHash('sha1').update(fs.readFileSync(lockFile)).digest('hex');
|
|
101
|
+
const stampHash = fs.readFileSync(stampFile, 'utf8').trim();
|
|
102
|
+
if (currentHash === stampHash) {
|
|
103
|
+
if (options.verbose) {
|
|
104
|
+
console.log(chalk.gray(` Skipping npm install in ${basename} (package-lock.json unchanged)`));
|
|
105
|
+
}
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
92
110
|
const spinner = ora(`Installing npm modules in ${basename}...`).start();
|
|
93
111
|
|
|
94
112
|
try {
|
|
95
|
-
const hasLock = fs.existsSync(path.join(dir, 'package-lock.json'));
|
|
96
113
|
const cmd = hasLock ? 'ci' : 'install';
|
|
97
114
|
await new Promise((resolve, reject) => {
|
|
98
115
|
const proc = spawn('npm', [cmd], {
|
|
@@ -114,6 +131,16 @@ async function runNpmInstall(config, options) {
|
|
|
114
131
|
reject(err);
|
|
115
132
|
});
|
|
116
133
|
});
|
|
134
|
+
|
|
135
|
+
// Write stamp so we can skip next time if package-lock.json is unchanged
|
|
136
|
+
if (hasLock) {
|
|
137
|
+
try {
|
|
138
|
+
const hash = crypto.createHash('sha1').update(fs.readFileSync(lockFile)).digest('hex');
|
|
139
|
+
fs.writeFileSync(stampFile, hash + '\n');
|
|
140
|
+
} catch {
|
|
141
|
+
// Stamp write failure is non-fatal — we'll just reinstall next time
|
|
142
|
+
}
|
|
143
|
+
}
|
|
117
144
|
} catch (err) {
|
|
118
145
|
throw err;
|
|
119
146
|
}
|
package/lib/sass-compiler.js
CHANGED
|
@@ -141,7 +141,21 @@ async function ensureDir(filePath) {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
/**
|
|
144
|
-
* Compile a single Sass file
|
|
144
|
+
* Compile a single Sass file in an isolated dart-sass compiler instance.
|
|
145
|
+
*
|
|
146
|
+
* Uses `sass.initAsyncCompiler()` instead of the module-level
|
|
147
|
+
* `sass.compileAsync()` to guarantee no shared state between concurrent
|
|
148
|
+
* compilations. The module-level singleton queues all calls through a
|
|
149
|
+
* single long-running dart-sass worker; in that model any subtle stateful
|
|
150
|
+
* behavior (import caching, in-flight deps, etc.) can bleed from one
|
|
151
|
+
* compilation's output into another's when we run a chunk in parallel.
|
|
152
|
+
*
|
|
153
|
+
* The symptom was stylesheets ending up with rules that their source
|
|
154
|
+
* file never imported (e.g. achrnews `application-v2.css` getting print
|
|
155
|
+
* rules from `jade-bnp-print.scss`). With a per-file isolated compiler,
|
|
156
|
+
* each file is compiled in its own worker, disposed when done — no
|
|
157
|
+
* possible cross-contamination vector.
|
|
158
|
+
*
|
|
145
159
|
* @param {string} src - Source file path
|
|
146
160
|
* @param {string} dest - Destination file path
|
|
147
161
|
* @param {Object} options - Compilation options
|
|
@@ -163,8 +177,10 @@ async function compileFile(src, dest, options = {}) {
|
|
|
163
177
|
importers.push(adaptLegacyImporter(legacyImporter));
|
|
164
178
|
}
|
|
165
179
|
|
|
180
|
+
let compiler = null;
|
|
166
181
|
try {
|
|
167
|
-
|
|
182
|
+
compiler = await sass.initAsyncCompiler();
|
|
183
|
+
const result = await compiler.compileAsync(src, {
|
|
168
184
|
style,
|
|
169
185
|
sourceMap,
|
|
170
186
|
loadPaths,
|
|
@@ -187,6 +203,14 @@ async function compileFile(src, dest, options = {}) {
|
|
|
187
203
|
return { src, dest, success: true };
|
|
188
204
|
} catch (error) {
|
|
189
205
|
return { src, dest, success: false, error };
|
|
206
|
+
} finally {
|
|
207
|
+
if (compiler) {
|
|
208
|
+
try {
|
|
209
|
+
await compiler.dispose();
|
|
210
|
+
} catch {
|
|
211
|
+
// Disposal errors are not actionable; compiler is going away.
|
|
212
|
+
}
|
|
213
|
+
}
|
|
190
214
|
}
|
|
191
215
|
}
|
|
192
216
|
|
|
@@ -198,7 +222,11 @@ async function compileFile(src, dest, options = {}) {
|
|
|
198
222
|
*/
|
|
199
223
|
async function compileSass(config, options = {}) {
|
|
200
224
|
const {
|
|
201
|
-
|
|
225
|
+
// Serial by default. compileFile() now spawns an isolated dart-sass
|
|
226
|
+
// compiler per file so concurrency wouldn't actually share state, but
|
|
227
|
+
// running serial gives us deterministic output ordering and bounded
|
|
228
|
+
// memory use. --parallel in cli.js still bumps this to 4 if needed.
|
|
229
|
+
maxConcurrency = 1,
|
|
202
230
|
verbose = false,
|
|
203
231
|
} = options;
|
|
204
232
|
|
package/package.json
CHANGED