@knighted/css 1.0.0-alpha.4 → 1.0.0-rc.0

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.
@@ -1,25 +1,103 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pitch = void 0;
3
4
  const css_js_1 = require("./css.cjs");
4
5
  const DEFAULT_EXPORT_NAME = 'knightedCss';
6
+ const COMBINED_QUERY_FLAG = 'combined';
5
7
  const loader = async function loader(source) {
6
- const rawOptions = (typeof this.getOptions === 'function' ? this.getOptions() : {});
7
- const cssOptions = rawOptions;
8
- const normalizedOptions = {
9
- ...cssOptions,
10
- cwd: cssOptions.cwd ?? this.rootContext ?? process.cwd(),
11
- };
12
- const { css, files } = await (0, css_js_1.cssWithMeta)(this.resourcePath, normalizedOptions);
13
- const uniqueFiles = new Set([this.resourcePath, ...files]);
14
- for (const file of uniqueFiles) {
15
- this.addDependency(file);
16
- }
17
- const input = typeof source === 'string' ? source : source.toString('utf8');
18
- const injection = `\n\nexport const ${DEFAULT_EXPORT_NAME} = ${JSON.stringify(css)};\n`;
8
+ const cssOptions = resolveCssOptions(this);
9
+ const css = await extractCss(this, cssOptions);
10
+ const injection = buildInjection(css);
11
+ const input = toSourceString(source);
19
12
  const isStyleModule = this.resourcePath.endsWith('.css.ts');
20
- const output = isStyleModule
21
- ? `${injection}export default {};\n`
22
- : `${input}${injection}`;
23
- return output;
13
+ return isStyleModule ? `${injection}export default {};\n` : `${input}${injection}`;
24
14
  };
15
+ const pitch = function pitch() {
16
+ if (!hasCombinedQuery(this.resourceQuery)) {
17
+ return;
18
+ }
19
+ const request = buildProxyRequest(this);
20
+ const cssOptions = resolveCssOptions(this);
21
+ return extractCss(this, cssOptions).then(css => createCombinedModule(request, css));
22
+ };
23
+ exports.pitch = pitch;
24
+ loader.pitch = exports.pitch;
25
25
  exports.default = loader;
26
+ function resolveCssOptions(ctx) {
27
+ const rawOptions = (typeof ctx.getOptions === 'function' ? ctx.getOptions() : {});
28
+ return {
29
+ ...rawOptions,
30
+ cwd: rawOptions.cwd ?? ctx.rootContext ?? process.cwd(),
31
+ };
32
+ }
33
+ async function extractCss(ctx, options) {
34
+ const { css, files } = await (0, css_js_1.cssWithMeta)(ctx.resourcePath, options);
35
+ const uniqueFiles = new Set([ctx.resourcePath, ...files]);
36
+ for (const file of uniqueFiles) {
37
+ ctx.addDependency(file);
38
+ }
39
+ return css;
40
+ }
41
+ function toSourceString(source) {
42
+ return typeof source === 'string' ? source : source.toString('utf8');
43
+ }
44
+ function buildInjection(css) {
45
+ return `\n\nexport const ${DEFAULT_EXPORT_NAME} = ${JSON.stringify(css)};\n`;
46
+ }
47
+ function hasCombinedQuery(query) {
48
+ if (!query)
49
+ return false;
50
+ const trimmed = query.startsWith('?') ? query.slice(1) : query;
51
+ if (!trimmed)
52
+ return false;
53
+ return trimmed
54
+ .split('&')
55
+ .filter(Boolean)
56
+ .some(part => isQueryFlag(part, COMBINED_QUERY_FLAG));
57
+ }
58
+ function buildProxyRequest(ctx) {
59
+ const sanitizedQuery = buildSanitizedQuery(ctx.resourceQuery);
60
+ const request = `${ctx.resourcePath}${sanitizedQuery}`;
61
+ const context = ctx.context ?? ctx.rootContext ?? process.cwd();
62
+ if (ctx.utils && typeof ctx.utils.contextify === 'function') {
63
+ return ctx.utils.contextify(context, request);
64
+ }
65
+ return request;
66
+ }
67
+ function buildSanitizedQuery(query) {
68
+ if (!query)
69
+ return '';
70
+ const entries = splitQuery(query).filter(part => {
71
+ return !isQueryFlag(part, COMBINED_QUERY_FLAG) && !isQueryFlag(part, 'knighted-css');
72
+ });
73
+ return entries.length > 0 ? `?${entries.join('&')}` : '';
74
+ }
75
+ function splitQuery(query) {
76
+ const trimmed = query.startsWith('?') ? query.slice(1) : query;
77
+ if (!trimmed)
78
+ return [];
79
+ return trimmed.split('&').filter(Boolean);
80
+ }
81
+ function isQueryFlag(entry, flag) {
82
+ const [rawKey] = entry.split('=');
83
+ try {
84
+ return decodeURIComponent(rawKey) === flag;
85
+ }
86
+ catch {
87
+ return rawKey === flag;
88
+ }
89
+ }
90
+ function createCombinedModule(request, css) {
91
+ const requestLiteral = JSON.stringify(request);
92
+ const defaultExport = `const __knightedDefault =
93
+ typeof __knightedModule.default !== 'undefined'
94
+ ? __knightedModule.default
95
+ : __knightedModule;`;
96
+ return [
97
+ `import * as __knightedModule from ${requestLiteral};`,
98
+ `export * from ${requestLiteral};`,
99
+ defaultExport,
100
+ 'export default __knightedDefault;',
101
+ buildInjection(css),
102
+ ].join('\n');
103
+ }
@@ -1,6 +1,10 @@
1
- import type { LoaderDefinitionFunction } from 'webpack';
1
+ import type { LoaderDefinitionFunction, PitchLoaderDefinitionFunction } from 'webpack';
2
2
  import { type CssOptions } from './css.cjs';
3
+ export type KnightedCssCombinedModule<TModule> = TModule & {
4
+ knightedCss: string;
5
+ };
3
6
  export interface KnightedCssLoaderOptions extends CssOptions {
4
7
  }
5
8
  declare const loader: LoaderDefinitionFunction<KnightedCssLoaderOptions>;
9
+ export declare const pitch: PitchLoaderDefinitionFunction<KnightedCssLoaderOptions>;
6
10
  export default loader;
package/dist/loader.d.ts CHANGED
@@ -1,6 +1,10 @@
1
- import type { LoaderDefinitionFunction } from 'webpack';
1
+ import type { LoaderDefinitionFunction, PitchLoaderDefinitionFunction } from 'webpack';
2
2
  import { type CssOptions } from './css.js';
3
+ export type KnightedCssCombinedModule<TModule> = TModule & {
4
+ knightedCss: string;
5
+ };
3
6
  export interface KnightedCssLoaderOptions extends CssOptions {
4
7
  }
5
8
  declare const loader: LoaderDefinitionFunction<KnightedCssLoaderOptions>;
9
+ export declare const pitch: PitchLoaderDefinitionFunction<KnightedCssLoaderOptions>;
6
10
  export default loader;
package/dist/loader.js CHANGED
@@ -1,23 +1,99 @@
1
1
  import { cssWithMeta } from './css.js';
2
2
  const DEFAULT_EXPORT_NAME = 'knightedCss';
3
+ const COMBINED_QUERY_FLAG = 'combined';
3
4
  const loader = async function loader(source) {
4
- const rawOptions = (typeof this.getOptions === 'function' ? this.getOptions() : {});
5
- const cssOptions = rawOptions;
6
- const normalizedOptions = {
7
- ...cssOptions,
8
- cwd: cssOptions.cwd ?? this.rootContext ?? process.cwd(),
9
- };
10
- const { css, files } = await cssWithMeta(this.resourcePath, normalizedOptions);
11
- const uniqueFiles = new Set([this.resourcePath, ...files]);
12
- for (const file of uniqueFiles) {
13
- this.addDependency(file);
14
- }
15
- const input = typeof source === 'string' ? source : source.toString('utf8');
16
- const injection = `\n\nexport const ${DEFAULT_EXPORT_NAME} = ${JSON.stringify(css)};\n`;
5
+ const cssOptions = resolveCssOptions(this);
6
+ const css = await extractCss(this, cssOptions);
7
+ const injection = buildInjection(css);
8
+ const input = toSourceString(source);
17
9
  const isStyleModule = this.resourcePath.endsWith('.css.ts');
18
- const output = isStyleModule
19
- ? `${injection}export default {};\n`
20
- : `${input}${injection}`;
21
- return output;
10
+ return isStyleModule ? `${injection}export default {};\n` : `${input}${injection}`;
22
11
  };
12
+ export const pitch = function pitch() {
13
+ if (!hasCombinedQuery(this.resourceQuery)) {
14
+ return;
15
+ }
16
+ const request = buildProxyRequest(this);
17
+ const cssOptions = resolveCssOptions(this);
18
+ return extractCss(this, cssOptions).then(css => createCombinedModule(request, css));
19
+ };
20
+ loader.pitch = pitch;
23
21
  export default loader;
22
+ function resolveCssOptions(ctx) {
23
+ const rawOptions = (typeof ctx.getOptions === 'function' ? ctx.getOptions() : {});
24
+ return {
25
+ ...rawOptions,
26
+ cwd: rawOptions.cwd ?? ctx.rootContext ?? process.cwd(),
27
+ };
28
+ }
29
+ async function extractCss(ctx, options) {
30
+ const { css, files } = await cssWithMeta(ctx.resourcePath, options);
31
+ const uniqueFiles = new Set([ctx.resourcePath, ...files]);
32
+ for (const file of uniqueFiles) {
33
+ ctx.addDependency(file);
34
+ }
35
+ return css;
36
+ }
37
+ function toSourceString(source) {
38
+ return typeof source === 'string' ? source : source.toString('utf8');
39
+ }
40
+ function buildInjection(css) {
41
+ return `\n\nexport const ${DEFAULT_EXPORT_NAME} = ${JSON.stringify(css)};\n`;
42
+ }
43
+ function hasCombinedQuery(query) {
44
+ if (!query)
45
+ return false;
46
+ const trimmed = query.startsWith('?') ? query.slice(1) : query;
47
+ if (!trimmed)
48
+ return false;
49
+ return trimmed
50
+ .split('&')
51
+ .filter(Boolean)
52
+ .some(part => isQueryFlag(part, COMBINED_QUERY_FLAG));
53
+ }
54
+ function buildProxyRequest(ctx) {
55
+ const sanitizedQuery = buildSanitizedQuery(ctx.resourceQuery);
56
+ const request = `${ctx.resourcePath}${sanitizedQuery}`;
57
+ const context = ctx.context ?? ctx.rootContext ?? process.cwd();
58
+ if (ctx.utils && typeof ctx.utils.contextify === 'function') {
59
+ return ctx.utils.contextify(context, request);
60
+ }
61
+ return request;
62
+ }
63
+ function buildSanitizedQuery(query) {
64
+ if (!query)
65
+ return '';
66
+ const entries = splitQuery(query).filter(part => {
67
+ return !isQueryFlag(part, COMBINED_QUERY_FLAG) && !isQueryFlag(part, 'knighted-css');
68
+ });
69
+ return entries.length > 0 ? `?${entries.join('&')}` : '';
70
+ }
71
+ function splitQuery(query) {
72
+ const trimmed = query.startsWith('?') ? query.slice(1) : query;
73
+ if (!trimmed)
74
+ return [];
75
+ return trimmed.split('&').filter(Boolean);
76
+ }
77
+ function isQueryFlag(entry, flag) {
78
+ const [rawKey] = entry.split('=');
79
+ try {
80
+ return decodeURIComponent(rawKey) === flag;
81
+ }
82
+ catch {
83
+ return rawKey === flag;
84
+ }
85
+ }
86
+ function createCombinedModule(request, css) {
87
+ const requestLiteral = JSON.stringify(request);
88
+ const defaultExport = `const __knightedDefault =
89
+ typeof __knightedModule.default !== 'undefined'
90
+ ? __knightedModule.default
91
+ : __knightedModule;`;
92
+ return [
93
+ `import * as __knightedModule from ${requestLiteral};`,
94
+ `export * from ${requestLiteral};`,
95
+ defaultExport,
96
+ 'export default __knightedDefault;',
97
+ buildInjection(css),
98
+ ].join('\n');
99
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knighted/css",
3
- "version": "1.0.0-alpha.4",
3
+ "version": "1.0.0-rc.0",
4
4
  "description": "A build-time utility that traverses JavaScript/TypeScript module dependency graphs to extract, compile, and optimize all imported CSS into a single, in-memory string.",
5
5
  "type": "module",
6
6
  "main": "./dist/css.js",