Skip to content

Commit f59b907

Browse files
committed
2.2.12
1 parent d7bf21f commit f59b907

File tree

5 files changed

+140
-28
lines changed

5 files changed

+140
-28
lines changed

changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## V2.2.12
2+
- only use cache in watch mode
3+
- refine inject logic
4+
- add example of custom inject to tests
5+
16
## V2.2.11
27
- replace `process.memoryUsage.rss()` to `process.memoryUsage().rss` to support Nodejs<15.6.0
38

lib/plugin.js

Lines changed: 95 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const path = require('path');
22
const { createHash } = require('crypto');
3-
const { readFile, appendFile } = require('fs/promises');
3+
const { readFile, writeFile, unlink } = require('fs/promises');
44
const {
55
getLogger,
66
buildInjectCode,
@@ -36,8 +36,8 @@ const buildCssModulesJs = async ({ fullPath, options, build }) => {
3636
const bundleConfig = {
3737
filename: fullPath,
3838
code: originCss,
39-
minify: true,
40-
sourceMap: !options.inject,
39+
minify: false,
40+
sourceMap: true,
4141
cssModules: true,
4242
analyzeDependencies: false
4343
};
@@ -179,8 +179,10 @@ const onLoadModulesCss = async (build, options, args) => {
179179

180180
log(`loading ${rpath}${args.suffix}`);
181181

182-
log(`checking cache for`, rpath);
183-
const cached = await cache.get(absPath);
182+
const useCache = build.initialOptions.watch;
183+
184+
useCache && log(`checking cache for`, rpath);
185+
const cached = useCache && (await cache.get(absPath));
184186
if (cached) {
185187
log('return build cache for', rpath);
186188
return cached;
@@ -208,8 +210,11 @@ const onLoadModulesCss = async (build, options, args) => {
208210
contents: js,
209211
loader: 'js'
210212
};
211-
await cache.set(absPath, result, originCss);
212-
log(`add build result to cache for ${rpath}`);
213+
214+
if (useCache) {
215+
await cache.set(absPath, result, originCss);
216+
log(`add build result to cache for ${rpath}`);
217+
}
213218

214219
return result;
215220
};
@@ -275,13 +280,82 @@ const onLoadBuiltModulesCss = async ({ pluginData }, build) => {
275280
* @param {import('esbuild').BuildResult} result
276281
*/
277282
const onEnd = async (build, options, result) => {
278-
const { buildId, buildRoot, cache } = build.context;
283+
const { initialOptions, context, esbuild } = build;
284+
const { buildId, buildRoot } = context;
279285
const log = getLogger(build);
280286

281-
if (options.inject === true || typeof options.inject === 'string') {
287+
if (options.inject) {
288+
const {
289+
charset = 'utf8',
290+
outdir,
291+
sourceRoot,
292+
sourcemap,
293+
sourcesContent,
294+
entryPoints,
295+
minify,
296+
logLevel,
297+
format,
298+
target,
299+
external,
300+
publicPath
301+
} = initialOptions;
302+
const absOutdir = path.isAbsolute(outdir) ? outdir : path.resolve(buildRoot, outdir);
303+
304+
const transformCss = async (css) => {
305+
const r = await esbuild.transform(css, {
306+
charset,
307+
loader: 'css',
308+
sourcemap: false,
309+
minify: true,
310+
logLevel,
311+
format,
312+
target
313+
});
314+
return r.code;
315+
};
316+
317+
const buildJs = async (entryName, entryPath, jsCode) => {
318+
const r = (p) => `./${path.relative(absOutdir, p).split(path.sep).join(path.posix.sep)}`;
319+
const imports = `import "${r(entryPath)}";`;
320+
if ((sourceRoot || publicPath) && sourcemap) {
321+
const sp = sourceRoot || publicPath;
322+
const fixedSourceRoot = sp.endsWith('/') ? sp : sp + '/';
323+
const entryContent = await readFile(entryPath, { encoding: 'utf8' });
324+
await writeFile(
325+
entryPath,
326+
entryContent.replace(`sourceMappingURL=${fixedSourceRoot}`, 'sourceMappingURL='),
327+
{ encoding: 'utf8' }
328+
);
329+
}
330+
const tmpJsCode = `${imports}\n${jsCode}`;
331+
const tmpJsPath = path.resolve(absOutdir, '.build.inject.js');
332+
await writeFile(tmpJsPath, tmpJsCode, { encoding: 'utf8' });
333+
await esbuild.build({
334+
charset,
335+
absWorkingDir: absOutdir,
336+
write: true,
337+
allowOverwrite: true,
338+
treeShaking: false,
339+
logLevel,
340+
format,
341+
target,
342+
minify,
343+
sourceRoot,
344+
publicPath,
345+
sourcemap,
346+
sourcesContent,
347+
entryPoints: {
348+
[entryName]: tmpJsPath
349+
},
350+
outdir: absOutdir,
351+
bundle: true,
352+
external
353+
});
354+
await unlink(tmpJsPath);
355+
};
356+
282357
const cssContents = [];
283358

284-
const { entryPoints } = build.initialOptions;
285359
let entriesArray = [];
286360
if (Array.isArray(entryPoints)) {
287361
entriesArray = [...entryPoints];
@@ -296,35 +370,35 @@ const onEnd = async (build, options, result) => {
296370

297371
log('entries:', entries);
298372

299-
let injectTo = null;
373+
let entryToInject = null;
300374
const outputs = Object.keys(result.metafile?.outputs ?? []);
301375

302376
await Promise.all(
303377
outputs.map(async (f) => {
304378
if (
305-
!injectTo &&
379+
!entryToInject &&
306380
result.metafile.outputs[f].entryPoint &&
307381
entries.includes(path.resolve(buildRoot, result.metafile.outputs[f].entryPoint)) &&
308-
path.extname(f) === '.js'
382+
['.js', '.mjs', '.cjs'].includes(path.extname(f))
309383
) {
310-
injectTo = path.resolve(buildRoot, f);
384+
entryToInject = path.resolve(buildRoot, f);
311385
}
312386
if (path.extname(f) === '.css') {
313387
const fullpath = path.resolve(buildRoot, f);
314388
const css = await readFile(fullpath, { encoding: 'utf8' });
315-
cssContents.push(`${css}`);
389+
const transformed = await transformCss(css);
390+
cssContents.push(`${transformed}`);
316391
}
317392
})
318393
);
319394

320-
log('inject css to', path.relative(buildRoot, injectTo));
321-
322-
if (injectTo && cssContents.length) {
323-
const allCss = cssContents.join('');
395+
if (entryToInject && cssContents.length) {
396+
log('inject css to', path.relative(buildRoot, entryToInject));
397+
const entryName = path.basename(entryToInject, path.extname(entryToInject));
398+
const allCss = cssContents.join('\n');
324399
const container = typeof options.inject === 'string' ? options.inject : 'head';
325400
const injectedCode = buildInjectCode(container, allCss, buildId, options);
326-
327-
await appendFile(injectTo, injectedCode, { encoding: 'utf-8' });
401+
await buildJs(entryName, entryToInject, injectedCode);
328402
}
329403
}
330404

lib/utils.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,8 @@ const buildInjectCode = (injectToSelector = 'head', css, digest, options) => {
3636
if (typeof options.inject === 'function') {
3737
return `
3838
(function(){
39-
const css = \`${css}\`;
40-
const digest = \`${digest}\`;
4139
const doInject = () => {
42-
${options.inject(css, digest)};
40+
${options.inject(css, digest)}
4341
delete window.__inject_${digest}__;
4442
};
4543
window.__inject_${digest}__ = doInject;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "esbuild-css-modules-plugin",
3-
"version": "2.2.11",
3+
"version": "2.2.12",
44
"description": "A esbuild plugin to bundle css modules into js(x)/ts(x).",
55
"main": "index.js",
66
"keywords": [

test/test.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ fse.emptyDirSync('./dist');
7878
},
7979
entryNames: '[name]-[hash]',
8080
format: 'esm',
81-
target: ['es2020'],
81+
target: ['esnext'],
8282
bundle: true,
83-
minify: false,
83+
minify: true,
8484
sourcemap: true,
8585
publicPath: 'https://my.domain/static/',
8686
external: ['react', 'react-dom'],
@@ -97,11 +97,46 @@ fse.emptyDirSync('./dist');
9797
});
9898
console.log('[test][esbuild:bundle:v2] done, please check `test/dist/bundle-v2-inject`', '\n');
9999

100+
await esbuild.build({
101+
entryPoints: {
102+
['custom-entry-name']: 'app.jsx'
103+
},
104+
entryNames: '[name]-[hash]',
105+
format: 'esm',
106+
target: ['esnext'],
107+
bundle: true,
108+
minify: false,
109+
sourcemap: true,
110+
publicPath: 'https://my.domain/static/',
111+
external: ['react', 'react-dom'],
112+
outdir: './dist/bundle-v2-custom-inject',
113+
write: true,
114+
loader: {
115+
'.jpg': 'dataurl'
116+
},
117+
plugins: [cssModulesPlugin({
118+
v2: true,
119+
inject: (css, digest) => {
120+
return `
121+
const styleId = 'style_${digest}';
122+
if (!document.getElementById(styleId)) {
123+
const styleEle = document.createElement('style');
124+
styleEle.id = styleId;
125+
styleEle.textContent = \`${css.replace(/\n/g, '')}\`;
126+
document.head.appendChild(styleEle);
127+
}
128+
`
129+
}
130+
})],
131+
logLevel: 'debug'
132+
});
133+
console.log('[test][esbuild:bundle:v2] done, please check `test/dist/bundle-v2-custom-inject`', '\n');
134+
100135
await esbuild.build({
101136
entryPoints: ['app.jsx'],
102137
entryNames: '[name]-[hash]',
103138
format: 'esm',
104-
target: ['es2020'],
139+
target: ['esnext'],
105140
bundle: true,
106141
minify: false,
107142
sourcemap: true,

0 commit comments

Comments
 (0)