Skip to content

Commit e391bae

Browse files
Allow custom identifier hashing (#1160)
1 parent cb2132f commit e391bae

File tree

9 files changed

+122
-6
lines changed

9 files changed

+122
-6
lines changed

.changeset/curly-lies-flash.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@vanilla-extract/css': minor
3+
'@vanilla-extract/webpack-plugin': minor
4+
'@vanilla-extract/esbuild-plugin': minor
5+
'@vanilla-extract/rollup-plugin': minor
6+
'@vanilla-extract/vite-plugin': minor
7+
'@vanilla-extract/next-plugin': minor
8+
---
9+
10+
Users can now provide a custom identifier hashing function

packages/css/src/identifier.test.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { setFileScope, endFileScope } from './fileScope';
1+
import { removeAdapter, setAdapter } from './adapter';
2+
import { endFileScope, setFileScope } from './fileScope';
23
import { generateIdentifier } from './identifier';
34

45
describe('identifier', () => {
@@ -57,4 +58,43 @@ describe('identifier', () => {
5758
).toMatchInlineSnapshot(`"_18bazsm6"`);
5859
});
5960
});
61+
62+
describe('with custom callback', () => {
63+
beforeAll(() => {
64+
setFileScope('path/to/file.css.ts', 'packagetest');
65+
setAdapter({
66+
appendCss: () => {},
67+
registerClassName: () => {},
68+
onEndFileScope: () => {},
69+
registerComposition: () => {},
70+
markCompositionUsed: () => {},
71+
getIdentOption:
72+
() =>
73+
({ hash, debugId, filePath, packageName }) => {
74+
const filenameWithExtension = filePath?.split('/').pop();
75+
const filenameWithoutExtension =
76+
filenameWithExtension?.split('.')?.[0];
77+
78+
return `abc_${debugId}_${hash}_${packageName}_${filenameWithoutExtension}`;
79+
},
80+
});
81+
});
82+
83+
afterAll(() => {
84+
removeAdapter();
85+
endFileScope();
86+
});
87+
88+
it('defers to a custom callback', () => {
89+
expect(generateIdentifier(`a`)).toMatchInlineSnapshot(
90+
`"abc_a_s0xkdr0_packagetest_file"`,
91+
);
92+
});
93+
94+
it('rejects invalid identifiers', () => {
95+
// getIdentOption() does not remove spaces from the debug info so the
96+
// resulting identifier should be invalid here.
97+
expect(() => generateIdentifier(`a b`)).toThrow();
98+
});
99+
});
60100
});

packages/css/src/identifier.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ function getDevPrefix({
2828
return parts.join('_');
2929
}
3030

31+
function normalizeIdentifier(identifier: string) {
32+
return identifier.match(/^[0-9]/) ? `_${identifier}` : identifier;
33+
}
34+
3135
interface GenerateIdentifierOptions {
3236
debugId?: string;
3337
debugFileName?: boolean;
@@ -38,6 +42,7 @@ export function generateIdentifier(options?: GenerateIdentifierOptions): string;
3842
export function generateIdentifier(
3943
arg?: string | GenerateIdentifierOptions,
4044
): string {
45+
const identOption = getIdentOption();
4146
const { debugId, debugFileName = true } = {
4247
...(typeof arg === 'string' ? { debugId: arg } : null),
4348
...(typeof arg === 'object' ? arg : null),
@@ -53,13 +58,31 @@ export function generateIdentifier(
5358

5459
let identifier = `${fileScopeHash}${refCount}`;
5560

56-
if (getIdentOption() === 'debug') {
61+
if (identOption === 'debug') {
5762
const devPrefix = getDevPrefix({ debugId, debugFileName });
5863

5964
if (devPrefix) {
6065
identifier = `${devPrefix}__${identifier}`;
6166
}
67+
68+
return normalizeIdentifier(identifier);
6269
}
70+
if (typeof identOption === 'function') {
71+
identifier = identOption({
72+
hash: identifier,
73+
debugId,
74+
filePath,
75+
packageName,
76+
});
6377

64-
return identifier.match(/^[0-9]/) ? `_${identifier}` : identifier;
78+
if (!identifier.match(/^[A-Z_][0-9A-Z_]+$/i)) {
79+
throw new Error(
80+
`Identifier function returned invalid indentifier: "${identifier}"`,
81+
);
82+
}
83+
84+
return identifier;
85+
}
86+
87+
return normalizeIdentifier(identifier);
6588
}

packages/css/src/types.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import type { MapLeafNodes, CSSVarFunction } from '@vanilla-extract/private';
2-
import type { Properties, AtRule } from 'csstype';
1+
import type { CSSVarFunction, MapLeafNodes } from '@vanilla-extract/private';
2+
import type { AtRule, Properties } from 'csstype';
33

44
import type { SimplePseudos } from './simplePseudos';
55

@@ -120,7 +120,15 @@ export interface Composition {
120120
classList: string;
121121
}
122122

123-
type IdentOption = 'short' | 'debug';
123+
type CustomIdentFunction = (params: {
124+
hash: string;
125+
filePath: string;
126+
debugId?: string;
127+
packageName?: string;
128+
}) => string;
129+
130+
type IdentOption = 'short' | 'debug' | CustomIdentFunction;
131+
124132
export interface Adapter {
125133
appendCss: (css: CSS, fileScope: FileScope) => void;
126134
registerClassName: (className: string, fileScope: FileScope) => void;

site/docs/integrations/esbuild.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ Different formatting of identifiers (e.g. class names, keyframes, CSS Vars, etc)
100100

101101
- `short` identifiers are a 7+ character hash. e.g. `hnw5tz3`
102102
- `debug` identifiers contain human readable prefixes representing the owning filename and a potential rule level debug name. e.g. `myfile_mystyle_hnw5tz3`
103+
- A custom identifier function takes an object parameter with properties `hash`, `filePath`, `debugId`, and `packageName`, and returns a customized identifier. e.g.
104+
105+
```ts
106+
vanillaExtractPlugin({
107+
identifiers: ({ hash }) => `prefix_${hash}`
108+
});
109+
```
103110

104111
Each integration will set a default value based on the configuration options passed to the bundler.
105112

site/docs/integrations/next.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,12 @@ Different formatting of identifiers (e.g. class names, keyframes, CSS Vars, etc)
5757

5858
- `short` identifiers are a 7+ character hash. e.g. `hnw5tz3`
5959
- `debug` identifiers contain human readable prefixes representing the owning filename and a potential rule level debug name. e.g. `myfile_mystyle_hnw5tz3`
60+
- A custom identifier function takes an object parameter with properties `hash`, `filePath`, `debugId`, and `packageName`, and returns a customized identifier. e.g.
61+
62+
```ts
63+
const withVanillaExtract = createVanillaExtractPlugin({
64+
identifiers: ({ hash }) => `prefix_${hash}`
65+
});
66+
```
6067

6168
Each integration will set a default value based on the configuration options passed to the bundler.

site/docs/integrations/rollup.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ Different formatting of identifiers (e.g. class names, keyframes, CSS Vars, etc)
7676
7777
- `short` identifiers are a 7+ character hash. e.g. `hnw5tz3`
7878
- `debug` identifiers contain human readable prefixes representing the owning filename and a potential rule level debug name. e.g. `myfile_mystyle_hnw5tz3`
79+
- A custom identifier function takes an object parameter with properties `hash`, `filePath`, `debugId`, and `packageName`, and returns a customized identifier. e.g.
80+
81+
```ts
82+
vanillaExtractPlugin({
83+
identifiers: ({ hash }) => `prefix_${hash}`
84+
});
85+
```
7986
8087
Each integration will set a default value based on the configuration options passed to the bundler.
8188

site/docs/integrations/vite.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ Different formatting of identifiers (e.g. class names, keyframes, CSS Vars, etc)
5151

5252
- `short` identifiers are a 7+ character hash. e.g. `hnw5tz3`
5353
- `debug` identifiers contain human readable prefixes representing the owning filename and a potential rule level debug name. e.g. `myfile_mystyle_hnw5tz3`
54+
- A custom identifier function takes an object parameter with properties `hash`, `filePath`, `debugId`, and `packageName`, and returns a customized identifier. e.g.
55+
56+
```ts
57+
vanillaExtractPlugin({
58+
identifiers: ({ hash }) => `prefix_${hash}`
59+
});
60+
```
5461

5562
Each integration will set a default value based on the configuration options passed to the bundler.
5663

site/docs/integrations/webpack.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,12 @@ Different formatting of identifiers (e.g. class names, keyframes, CSS Vars, etc)
9191

9292
- `short` identifiers are a 7+ character hash. e.g. `hnw5tz3`
9393
- `debug` identifiers contain human readable prefixes representing the owning filename and a potential rule level debug name. e.g. `myfile_mystyle_hnw5tz3`
94+
- A custom identifier function takes an object parameter with properties `hash`, `filePath`, `debugId`, and `packageName`, and returns a customized identifier. e.g.
95+
96+
```ts
97+
VanillaExtractPlugin({
98+
identifiers: ({ hash }) => `prefix_${hash}`
99+
});
100+
```
94101

95102
Each integration will set a default value based on the configuration options passed to the bundler.

0 commit comments

Comments
 (0)