@vanilla-extract/vite-plugin 3.9.5 → 4.0.1

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,11 +1,10 @@
1
1
  import { Plugin } from 'vite';
2
- import { IdentifierOption, CompileOptions } from '@vanilla-extract/integration';
2
+ import { IdentifierOption } from '@vanilla-extract/integration';
3
3
 
4
4
  interface Options {
5
5
  identifiers?: IdentifierOption;
6
- emitCssInSsr?: boolean;
7
- esbuildOptions?: CompileOptions['esbuildOptions'];
6
+ unstable_mode?: 'transform' | 'emitCss';
8
7
  }
9
- declare function vanillaExtractPlugin({ identifiers, emitCssInSsr, esbuildOptions, }?: Options): Plugin;
8
+ declare function vanillaExtractPlugin({ identifiers, unstable_mode: mode, }?: Options): Plugin;
10
9
 
11
10
  export { vanillaExtractPlugin };
@@ -3,77 +3,72 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var path = require('path');
6
- var outdent = require('outdent');
7
6
  var integration = require('@vanilla-extract/integration');
8
7
 
9
8
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
10
9
 
11
10
  var path__default = /*#__PURE__*/_interopDefault(path);
12
- var outdent__default = /*#__PURE__*/_interopDefault(outdent);
13
11
 
14
- // Mostly copied from vite's implementation
15
- // https://github.com/vitejs/vite/blob/efec70f816b80e55b64255b32a5f120e1cf4e4be/packages/vite/src/node/plugins/css.ts
16
- const resolvePostcssConfig = async config => {
17
- var _config$css;
18
- // inline postcss config via vite config
19
- const inlineOptions = (_config$css = config.css) === null || _config$css === void 0 ? void 0 : _config$css.postcss;
20
- const inlineOptionsIsString = typeof inlineOptions === 'string';
21
- if (inlineOptions && !inlineOptionsIsString) {
22
- const options = {
23
- ...inlineOptions
24
- };
25
- delete options.plugins;
26
- return {
27
- options,
28
- plugins: inlineOptions.plugins || []
29
- };
30
- } else {
31
- try {
32
- const searchPath = typeof inlineOptions === 'string' ? inlineOptions : config.root;
33
- const postCssConfig = await (await import('postcss-load-config')).default({}, searchPath);
34
- return {
35
- options: postCssConfig.options,
36
- plugins: postCssConfig.plugins
37
- };
38
- } catch (e) {
39
- if (!/No PostCSS Config found/.test(e.message)) {
40
- throw e;
41
- }
42
- return null;
43
- }
44
- }
45
- };
46
-
47
- const styleUpdateEvent = fileId => `vanilla-extract-style-update:${fileId}`;
48
12
  const virtualExtCss = '.vanilla.css';
49
- const virtualExtJs = '.vanilla.js';
13
+ const isVirtualId = id => id.endsWith(virtualExtCss);
14
+ const fileIdToVirtualId = id => `${id}${virtualExtCss}`;
15
+ const virtualIdToFileId = virtualId => virtualId.slice(0, -virtualExtCss.length);
50
16
  function vanillaExtractPlugin({
51
17
  identifiers,
52
- emitCssInSsr,
53
- esbuildOptions
18
+ unstable_mode: mode = 'emitCss'
54
19
  } = {}) {
55
20
  let config;
21
+ let userConfig;
56
22
  let server;
57
- let postCssConfig;
58
- // We lazily load this utility from Vite
59
- let normalizePath;
60
- const cssMap = new Map();
61
- const hasEmitCssOverride = typeof emitCssInSsr === 'boolean';
62
- let resolvedEmitCssInSsr = hasEmitCssOverride ? emitCssInSsr : !!process.env.VITE_RSC_BUILD;
63
23
  let packageName;
64
- const getAbsoluteVirtualFileId = source => normalizePath(path__default["default"].join(config.root, source));
24
+ let compiler;
25
+ const getIdentOption = () => identifiers ?? (config.mode === 'production' ? 'short' : 'debug');
26
+ const getAbsoluteId = filePath => {
27
+ let resolvedId = filePath;
28
+ if (filePath.startsWith(config.root) ||
29
+ // In monorepos the absolute path will be outside of config.root, so we check that they have the same root on the file system
30
+ path__default["default"].isAbsolute(filePath) && filePath.split(path__default["default"].sep)[1] === config.root.split(path__default["default"].sep)[1]) {
31
+ resolvedId = filePath;
32
+ } else {
33
+ // In SSR mode we can have paths like /app/styles.css.ts
34
+ resolvedId = path__default["default"].join(config.root, filePath);
35
+ }
36
+ return integration.normalizePath(resolvedId);
37
+ };
38
+ function invalidateModule(absoluteId) {
39
+ if (!server) return;
40
+ const {
41
+ moduleGraph
42
+ } = server;
43
+ const modules = moduleGraph.getModulesByFile(absoluteId);
44
+ if (modules) {
45
+ for (const module of modules) {
46
+ moduleGraph.invalidateModule(module);
47
+
48
+ // Vite uses this timestamp to add `?t=` query string automatically for HMR.
49
+ module.lastHMRTimestamp = module.lastInvalidationTimestamp || Date.now();
50
+ }
51
+ }
52
+ }
53
+ function addWatchFiles(fromId, files) {
54
+ // We don't need to watch files in build mode
55
+ if (config.command === 'build' && !config.build.watch) {
56
+ return;
57
+ }
58
+ for (const file of files) {
59
+ if (!file.includes('node_modules') && integration.normalizePath(file) !== fromId) {
60
+ this.addWatchFile(file);
61
+ }
62
+ }
63
+ }
65
64
  return {
66
65
  name: 'vanilla-extract',
67
- enforce: 'pre',
68
66
  configureServer(_server) {
69
67
  server = _server;
70
68
  },
71
- config(_userConfig, env) {
72
- const include = env.command === 'serve' ? ['@vanilla-extract/css/injectStyles'] : [];
69
+ config(viteUserConfig) {
70
+ userConfig = viteUserConfig;
73
71
  return {
74
- optimizeDeps: {
75
- include
76
- },
77
72
  ssr: {
78
73
  external: ['@vanilla-extract/css', '@vanilla-extract/css/fileScope', '@vanilla-extract/css/adapter']
79
74
  }
@@ -82,151 +77,81 @@ function vanillaExtractPlugin({
82
77
  async configResolved(resolvedConfig) {
83
78
  config = resolvedConfig;
84
79
  packageName = integration.getPackageInfo(config.root).name;
85
- normalizePath = (await import('vite')).normalizePath;
86
- if (config.command === 'serve') {
87
- postCssConfig = await resolvePostcssConfig(config);
88
- }
89
- if (!hasEmitCssOverride && config.plugins.some(plugin => ['astro:build', 'remix', 'solid-start-server', 'vite-plugin-qwik', 'vite-plugin-svelte'].includes(plugin.name))) {
90
- resolvedEmitCssInSsr = true;
80
+ if (mode !== 'transform') {
81
+ var _userConfig$plugins;
82
+ compiler = integration.createCompiler({
83
+ root: config.root,
84
+ identifiers: getIdentOption(),
85
+ cssImportSpecifier: fileIdToVirtualId,
86
+ vitePlugins: (_userConfig$plugins = userConfig.plugins) === null || _userConfig$plugins === void 0 ? void 0 : _userConfig$plugins.flat().filter(plugin => typeof plugin === 'object' && plugin !== null && 'name' in plugin &&
87
+ // Prevent an infinite loop where the compiler creates a new instance of the plugin,
88
+ // which creates a new compiler, which creates a new instance of the plugin, etc.
89
+ plugin.name !== 'vanilla-extract' &&
90
+ // Skip Vitest plugins
91
+ plugin.name !== 'vitest' && !plugin.name.startsWith('vitest:'))
92
+ });
91
93
  }
92
94
  },
93
- resolveId(source) {
94
- const [validId, query] = source.split('?');
95
- if (!validId.endsWith(virtualExtCss) && !validId.endsWith(virtualExtJs)) {
96
- return;
97
- }
98
-
99
- // Absolute paths seem to occur often in monorepos, where files are
100
- // imported from outside the config root.
101
- const absoluteId = source.startsWith(config.root) ? source : getAbsoluteVirtualFileId(validId);
102
-
103
- // There should always be an entry in the `cssMap` here.
104
- // The only valid scenario for a missing one is if someone had written
105
- // a file in their app using the .vanilla.js/.vanilla.css extension
106
- if (cssMap.has(absoluteId)) {
107
- // Keep the original query string for HMR.
108
- return absoluteId + (query ? `?${query}` : '');
109
- }
95
+ buildEnd() {
96
+ var _compiler;
97
+ (_compiler = compiler) === null || _compiler === void 0 ? void 0 : _compiler.close();
110
98
  },
111
- load(id) {
112
- const [validId] = id.split('?');
113
- if (!cssMap.has(validId)) {
114
- return;
115
- }
116
- const css = cssMap.get(validId);
117
- if (typeof css !== 'string') {
118
- return;
119
- }
120
- if (validId.endsWith(virtualExtCss)) {
121
- return css;
122
- }
123
- return outdent__default["default"]`
124
- import { injectStyles } from '@vanilla-extract/css/injectStyles';
125
-
126
- const inject = (css) => injectStyles({
127
- fileScope: ${JSON.stringify({
128
- filePath: validId
129
- })},
130
- css
131
- });
132
-
133
- inject(${JSON.stringify(css)});
134
-
135
- if (import.meta.hot) {
136
- import.meta.hot.on('${styleUpdateEvent(validId)}', (css) => {
137
- inject(css);
138
- });
139
- }
140
- `;
141
- },
142
- async transform(code, id, ssrParam) {
99
+ async transform(code, id) {
143
100
  const [validId] = id.split('?');
144
101
  if (!integration.cssFileFilter.test(validId)) {
145
102
  return null;
146
103
  }
147
- const identOption = identifiers ?? (config.mode === 'production' ? 'short' : 'debug');
148
- let ssr;
149
- if (typeof ssrParam === 'boolean') {
150
- ssr = ssrParam;
151
- } else {
152
- ssr = ssrParam === null || ssrParam === void 0 ? void 0 : ssrParam.ssr;
153
- }
154
- if (ssr && !resolvedEmitCssInSsr) {
104
+ const identOption = getIdentOption();
105
+ if (mode === 'transform') {
155
106
  return integration.transform({
156
107
  source: code,
157
- filePath: normalizePath(validId),
108
+ filePath: integration.normalizePath(validId),
158
109
  rootPath: config.root,
159
110
  packageName,
160
111
  identOption
161
112
  });
162
113
  }
163
- const {
164
- source,
165
- watchFiles
166
- } = await integration.compile({
167
- filePath: validId,
168
- cwd: config.root,
169
- esbuildOptions,
170
- identOption
171
- });
172
- for (const file of watchFiles) {
173
- // In start mode, we need to prevent the file from rewatching itself.
174
- // If it's a `build --watch`, it needs to watch everything.
175
- if (config.command === 'build' || normalizePath(file) !== validId) {
176
- this.addWatchFile(file);
177
- }
178
- }
179
- const output = await integration.processVanillaFile({
180
- source,
181
- filePath: validId,
182
- identOption,
183
- serializeVirtualCssPath: async ({
184
- fileScope,
185
- source
186
- }) => {
187
- const rootRelativeId = `${fileScope.filePath}${config.command === 'build' || ssr && resolvedEmitCssInSsr ? virtualExtCss : virtualExtJs}`;
188
- const absoluteId = getAbsoluteVirtualFileId(rootRelativeId);
189
- let cssSource = source;
190
- if (postCssConfig) {
191
- const postCssResult = await (await import('postcss')).default(postCssConfig.plugins).process(source, {
192
- ...postCssConfig.options,
193
- from: undefined,
194
- map: false
195
- });
196
- cssSource = postCssResult.css;
197
- }
198
- if (server && cssMap.has(absoluteId) && cssMap.get(absoluteId) !== cssSource) {
199
- const {
200
- moduleGraph
201
- } = server;
202
- const modules = Array.from(moduleGraph.getModulesByFile(absoluteId) || []);
203
- for (const module of modules) {
204
- if (module) {
205
- moduleGraph.invalidateModule(module);
114
+ if (compiler) {
115
+ const absoluteId = getAbsoluteId(validId);
116
+ const {
117
+ source,
118
+ watchFiles
119
+ } = await compiler.processVanillaFile(absoluteId, {
120
+ outputCss: true
121
+ });
122
+ addWatchFiles.call(this, absoluteId, watchFiles);
206
123
 
207
- // Vite uses this timestamp to add `?t=` query string automatically for HMR.
208
- module.lastHMRTimestamp = module.lastInvalidationTimestamp || Date.now();
209
- }
210
- }
211
- server.ws.send({
212
- type: 'custom',
213
- event: styleUpdateEvent(absoluteId),
214
- data: cssSource
215
- });
124
+ // We have to invalidate the virtual module, not the real one we just transformed
125
+ invalidateModule(fileIdToVirtualId(absoluteId));
126
+ return {
127
+ code: source,
128
+ map: {
129
+ mappings: ''
216
130
  }
217
- cssMap.set(absoluteId, cssSource);
218
-
219
- // We use the root relative id here to ensure file contents (content-hashes)
220
- // are consistent across build machines
221
- return `import "${rootRelativeId}";`;
222
- }
223
- });
224
- return {
225
- code: output,
226
- map: {
227
- mappings: ''
228
- }
229
- };
131
+ };
132
+ }
133
+ },
134
+ resolveId(source) {
135
+ var _compiler2;
136
+ const [validId, query] = source.split('?');
137
+ if (!isVirtualId(validId)) return;
138
+ const absoluteId = getAbsoluteId(validId);
139
+ if ( // We should always have CSS for a file here.
140
+ // The only valid scenario for a missing one is if someone had written
141
+ // a file in their app using the .vanilla.js/.vanilla.css extension
142
+ (_compiler2 = compiler) !== null && _compiler2 !== void 0 && _compiler2.getCssForFile(virtualIdToFileId(absoluteId))) {
143
+ // Keep the original query string for HMR.
144
+ return absoluteId + (query ? `?${query}` : '');
145
+ }
146
+ },
147
+ load(id) {
148
+ const [validId] = id.split('?');
149
+ if (!isVirtualId(validId) || !compiler) return;
150
+ const absoluteId = getAbsoluteId(validId);
151
+ const {
152
+ css
153
+ } = compiler.getCssForFile(virtualIdToFileId(absoluteId));
154
+ return css;
230
155
  }
231
156
  };
232
157
  }
@@ -3,77 +3,72 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var path = require('path');
6
- var outdent = require('outdent');
7
6
  var integration = require('@vanilla-extract/integration');
8
7
 
9
8
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
10
9
 
11
10
  var path__default = /*#__PURE__*/_interopDefault(path);
12
- var outdent__default = /*#__PURE__*/_interopDefault(outdent);
13
11
 
14
- // Mostly copied from vite's implementation
15
- // https://github.com/vitejs/vite/blob/efec70f816b80e55b64255b32a5f120e1cf4e4be/packages/vite/src/node/plugins/css.ts
16
- const resolvePostcssConfig = async config => {
17
- var _config$css;
18
- // inline postcss config via vite config
19
- const inlineOptions = (_config$css = config.css) === null || _config$css === void 0 ? void 0 : _config$css.postcss;
20
- const inlineOptionsIsString = typeof inlineOptions === 'string';
21
- if (inlineOptions && !inlineOptionsIsString) {
22
- const options = {
23
- ...inlineOptions
24
- };
25
- delete options.plugins;
26
- return {
27
- options,
28
- plugins: inlineOptions.plugins || []
29
- };
30
- } else {
31
- try {
32
- const searchPath = typeof inlineOptions === 'string' ? inlineOptions : config.root;
33
- const postCssConfig = await (await import('postcss-load-config')).default({}, searchPath);
34
- return {
35
- options: postCssConfig.options,
36
- plugins: postCssConfig.plugins
37
- };
38
- } catch (e) {
39
- if (!/No PostCSS Config found/.test(e.message)) {
40
- throw e;
41
- }
42
- return null;
43
- }
44
- }
45
- };
46
-
47
- const styleUpdateEvent = fileId => `vanilla-extract-style-update:${fileId}`;
48
12
  const virtualExtCss = '.vanilla.css';
49
- const virtualExtJs = '.vanilla.js';
13
+ const isVirtualId = id => id.endsWith(virtualExtCss);
14
+ const fileIdToVirtualId = id => `${id}${virtualExtCss}`;
15
+ const virtualIdToFileId = virtualId => virtualId.slice(0, -virtualExtCss.length);
50
16
  function vanillaExtractPlugin({
51
17
  identifiers,
52
- emitCssInSsr,
53
- esbuildOptions
18
+ unstable_mode: mode = 'emitCss'
54
19
  } = {}) {
55
20
  let config;
21
+ let userConfig;
56
22
  let server;
57
- let postCssConfig;
58
- // We lazily load this utility from Vite
59
- let normalizePath;
60
- const cssMap = new Map();
61
- const hasEmitCssOverride = typeof emitCssInSsr === 'boolean';
62
- let resolvedEmitCssInSsr = hasEmitCssOverride ? emitCssInSsr : !!process.env.VITE_RSC_BUILD;
63
23
  let packageName;
64
- const getAbsoluteVirtualFileId = source => normalizePath(path__default["default"].join(config.root, source));
24
+ let compiler;
25
+ const getIdentOption = () => identifiers ?? (config.mode === 'production' ? 'short' : 'debug');
26
+ const getAbsoluteId = filePath => {
27
+ let resolvedId = filePath;
28
+ if (filePath.startsWith(config.root) ||
29
+ // In monorepos the absolute path will be outside of config.root, so we check that they have the same root on the file system
30
+ path__default["default"].isAbsolute(filePath) && filePath.split(path__default["default"].sep)[1] === config.root.split(path__default["default"].sep)[1]) {
31
+ resolvedId = filePath;
32
+ } else {
33
+ // In SSR mode we can have paths like /app/styles.css.ts
34
+ resolvedId = path__default["default"].join(config.root, filePath);
35
+ }
36
+ return integration.normalizePath(resolvedId);
37
+ };
38
+ function invalidateModule(absoluteId) {
39
+ if (!server) return;
40
+ const {
41
+ moduleGraph
42
+ } = server;
43
+ const modules = moduleGraph.getModulesByFile(absoluteId);
44
+ if (modules) {
45
+ for (const module of modules) {
46
+ moduleGraph.invalidateModule(module);
47
+
48
+ // Vite uses this timestamp to add `?t=` query string automatically for HMR.
49
+ module.lastHMRTimestamp = module.lastInvalidationTimestamp || Date.now();
50
+ }
51
+ }
52
+ }
53
+ function addWatchFiles(fromId, files) {
54
+ // We don't need to watch files in build mode
55
+ if (config.command === 'build' && !config.build.watch) {
56
+ return;
57
+ }
58
+ for (const file of files) {
59
+ if (!file.includes('node_modules') && integration.normalizePath(file) !== fromId) {
60
+ this.addWatchFile(file);
61
+ }
62
+ }
63
+ }
65
64
  return {
66
65
  name: 'vanilla-extract',
67
- enforce: 'pre',
68
66
  configureServer(_server) {
69
67
  server = _server;
70
68
  },
71
- config(_userConfig, env) {
72
- const include = env.command === 'serve' ? ['@vanilla-extract/css/injectStyles'] : [];
69
+ config(viteUserConfig) {
70
+ userConfig = viteUserConfig;
73
71
  return {
74
- optimizeDeps: {
75
- include
76
- },
77
72
  ssr: {
78
73
  external: ['@vanilla-extract/css', '@vanilla-extract/css/fileScope', '@vanilla-extract/css/adapter']
79
74
  }
@@ -82,151 +77,81 @@ function vanillaExtractPlugin({
82
77
  async configResolved(resolvedConfig) {
83
78
  config = resolvedConfig;
84
79
  packageName = integration.getPackageInfo(config.root).name;
85
- normalizePath = (await import('vite')).normalizePath;
86
- if (config.command === 'serve') {
87
- postCssConfig = await resolvePostcssConfig(config);
88
- }
89
- if (!hasEmitCssOverride && config.plugins.some(plugin => ['astro:build', 'remix', 'solid-start-server', 'vite-plugin-qwik', 'vite-plugin-svelte'].includes(plugin.name))) {
90
- resolvedEmitCssInSsr = true;
80
+ if (mode !== 'transform') {
81
+ var _userConfig$plugins;
82
+ compiler = integration.createCompiler({
83
+ root: config.root,
84
+ identifiers: getIdentOption(),
85
+ cssImportSpecifier: fileIdToVirtualId,
86
+ vitePlugins: (_userConfig$plugins = userConfig.plugins) === null || _userConfig$plugins === void 0 ? void 0 : _userConfig$plugins.flat().filter(plugin => typeof plugin === 'object' && plugin !== null && 'name' in plugin &&
87
+ // Prevent an infinite loop where the compiler creates a new instance of the plugin,
88
+ // which creates a new compiler, which creates a new instance of the plugin, etc.
89
+ plugin.name !== 'vanilla-extract' &&
90
+ // Skip Vitest plugins
91
+ plugin.name !== 'vitest' && !plugin.name.startsWith('vitest:'))
92
+ });
91
93
  }
92
94
  },
93
- resolveId(source) {
94
- const [validId, query] = source.split('?');
95
- if (!validId.endsWith(virtualExtCss) && !validId.endsWith(virtualExtJs)) {
96
- return;
97
- }
98
-
99
- // Absolute paths seem to occur often in monorepos, where files are
100
- // imported from outside the config root.
101
- const absoluteId = source.startsWith(config.root) ? source : getAbsoluteVirtualFileId(validId);
102
-
103
- // There should always be an entry in the `cssMap` here.
104
- // The only valid scenario for a missing one is if someone had written
105
- // a file in their app using the .vanilla.js/.vanilla.css extension
106
- if (cssMap.has(absoluteId)) {
107
- // Keep the original query string for HMR.
108
- return absoluteId + (query ? `?${query}` : '');
109
- }
95
+ buildEnd() {
96
+ var _compiler;
97
+ (_compiler = compiler) === null || _compiler === void 0 ? void 0 : _compiler.close();
110
98
  },
111
- load(id) {
112
- const [validId] = id.split('?');
113
- if (!cssMap.has(validId)) {
114
- return;
115
- }
116
- const css = cssMap.get(validId);
117
- if (typeof css !== 'string') {
118
- return;
119
- }
120
- if (validId.endsWith(virtualExtCss)) {
121
- return css;
122
- }
123
- return outdent__default["default"]`
124
- import { injectStyles } from '@vanilla-extract/css/injectStyles';
125
-
126
- const inject = (css) => injectStyles({
127
- fileScope: ${JSON.stringify({
128
- filePath: validId
129
- })},
130
- css
131
- });
132
-
133
- inject(${JSON.stringify(css)});
134
-
135
- if (import.meta.hot) {
136
- import.meta.hot.on('${styleUpdateEvent(validId)}', (css) => {
137
- inject(css);
138
- });
139
- }
140
- `;
141
- },
142
- async transform(code, id, ssrParam) {
99
+ async transform(code, id) {
143
100
  const [validId] = id.split('?');
144
101
  if (!integration.cssFileFilter.test(validId)) {
145
102
  return null;
146
103
  }
147
- const identOption = identifiers ?? (config.mode === 'production' ? 'short' : 'debug');
148
- let ssr;
149
- if (typeof ssrParam === 'boolean') {
150
- ssr = ssrParam;
151
- } else {
152
- ssr = ssrParam === null || ssrParam === void 0 ? void 0 : ssrParam.ssr;
153
- }
154
- if (ssr && !resolvedEmitCssInSsr) {
104
+ const identOption = getIdentOption();
105
+ if (mode === 'transform') {
155
106
  return integration.transform({
156
107
  source: code,
157
- filePath: normalizePath(validId),
108
+ filePath: integration.normalizePath(validId),
158
109
  rootPath: config.root,
159
110
  packageName,
160
111
  identOption
161
112
  });
162
113
  }
163
- const {
164
- source,
165
- watchFiles
166
- } = await integration.compile({
167
- filePath: validId,
168
- cwd: config.root,
169
- esbuildOptions,
170
- identOption
171
- });
172
- for (const file of watchFiles) {
173
- // In start mode, we need to prevent the file from rewatching itself.
174
- // If it's a `build --watch`, it needs to watch everything.
175
- if (config.command === 'build' || normalizePath(file) !== validId) {
176
- this.addWatchFile(file);
177
- }
178
- }
179
- const output = await integration.processVanillaFile({
180
- source,
181
- filePath: validId,
182
- identOption,
183
- serializeVirtualCssPath: async ({
184
- fileScope,
185
- source
186
- }) => {
187
- const rootRelativeId = `${fileScope.filePath}${config.command === 'build' || ssr && resolvedEmitCssInSsr ? virtualExtCss : virtualExtJs}`;
188
- const absoluteId = getAbsoluteVirtualFileId(rootRelativeId);
189
- let cssSource = source;
190
- if (postCssConfig) {
191
- const postCssResult = await (await import('postcss')).default(postCssConfig.plugins).process(source, {
192
- ...postCssConfig.options,
193
- from: undefined,
194
- map: false
195
- });
196
- cssSource = postCssResult.css;
197
- }
198
- if (server && cssMap.has(absoluteId) && cssMap.get(absoluteId) !== cssSource) {
199
- const {
200
- moduleGraph
201
- } = server;
202
- const modules = Array.from(moduleGraph.getModulesByFile(absoluteId) || []);
203
- for (const module of modules) {
204
- if (module) {
205
- moduleGraph.invalidateModule(module);
114
+ if (compiler) {
115
+ const absoluteId = getAbsoluteId(validId);
116
+ const {
117
+ source,
118
+ watchFiles
119
+ } = await compiler.processVanillaFile(absoluteId, {
120
+ outputCss: true
121
+ });
122
+ addWatchFiles.call(this, absoluteId, watchFiles);
206
123
 
207
- // Vite uses this timestamp to add `?t=` query string automatically for HMR.
208
- module.lastHMRTimestamp = module.lastInvalidationTimestamp || Date.now();
209
- }
210
- }
211
- server.ws.send({
212
- type: 'custom',
213
- event: styleUpdateEvent(absoluteId),
214
- data: cssSource
215
- });
124
+ // We have to invalidate the virtual module, not the real one we just transformed
125
+ invalidateModule(fileIdToVirtualId(absoluteId));
126
+ return {
127
+ code: source,
128
+ map: {
129
+ mappings: ''
216
130
  }
217
- cssMap.set(absoluteId, cssSource);
218
-
219
- // We use the root relative id here to ensure file contents (content-hashes)
220
- // are consistent across build machines
221
- return `import "${rootRelativeId}";`;
222
- }
223
- });
224
- return {
225
- code: output,
226
- map: {
227
- mappings: ''
228
- }
229
- };
131
+ };
132
+ }
133
+ },
134
+ resolveId(source) {
135
+ var _compiler2;
136
+ const [validId, query] = source.split('?');
137
+ if (!isVirtualId(validId)) return;
138
+ const absoluteId = getAbsoluteId(validId);
139
+ if ( // We should always have CSS for a file here.
140
+ // The only valid scenario for a missing one is if someone had written
141
+ // a file in their app using the .vanilla.js/.vanilla.css extension
142
+ (_compiler2 = compiler) !== null && _compiler2 !== void 0 && _compiler2.getCssForFile(virtualIdToFileId(absoluteId))) {
143
+ // Keep the original query string for HMR.
144
+ return absoluteId + (query ? `?${query}` : '');
145
+ }
146
+ },
147
+ load(id) {
148
+ const [validId] = id.split('?');
149
+ if (!isVirtualId(validId) || !compiler) return;
150
+ const absoluteId = getAbsoluteId(validId);
151
+ const {
152
+ css
153
+ } = compiler.getCssForFile(virtualIdToFileId(absoluteId));
154
+ return css;
230
155
  }
231
156
  };
232
157
  }
@@ -1,70 +1,66 @@
1
1
  import path from 'path';
2
- import outdent from 'outdent';
3
- import { getPackageInfo, cssFileFilter, transform, compile, processVanillaFile } from '@vanilla-extract/integration';
2
+ import { getPackageInfo, createCompiler, cssFileFilter, transform, normalizePath } from '@vanilla-extract/integration';
4
3
 
5
- // Mostly copied from vite's implementation
6
- // https://github.com/vitejs/vite/blob/efec70f816b80e55b64255b32a5f120e1cf4e4be/packages/vite/src/node/plugins/css.ts
7
- const resolvePostcssConfig = async config => {
8
- var _config$css;
9
- // inline postcss config via vite config
10
- const inlineOptions = (_config$css = config.css) === null || _config$css === void 0 ? void 0 : _config$css.postcss;
11
- const inlineOptionsIsString = typeof inlineOptions === 'string';
12
- if (inlineOptions && !inlineOptionsIsString) {
13
- const options = {
14
- ...inlineOptions
15
- };
16
- delete options.plugins;
17
- return {
18
- options,
19
- plugins: inlineOptions.plugins || []
20
- };
21
- } else {
22
- try {
23
- const searchPath = typeof inlineOptions === 'string' ? inlineOptions : config.root;
24
- const postCssConfig = await (await import('postcss-load-config')).default({}, searchPath);
25
- return {
26
- options: postCssConfig.options,
27
- plugins: postCssConfig.plugins
28
- };
29
- } catch (e) {
30
- if (!/No PostCSS Config found/.test(e.message)) {
31
- throw e;
32
- }
33
- return null;
34
- }
35
- }
36
- };
37
-
38
- const styleUpdateEvent = fileId => `vanilla-extract-style-update:${fileId}`;
39
4
  const virtualExtCss = '.vanilla.css';
40
- const virtualExtJs = '.vanilla.js';
5
+ const isVirtualId = id => id.endsWith(virtualExtCss);
6
+ const fileIdToVirtualId = id => `${id}${virtualExtCss}`;
7
+ const virtualIdToFileId = virtualId => virtualId.slice(0, -virtualExtCss.length);
41
8
  function vanillaExtractPlugin({
42
9
  identifiers,
43
- emitCssInSsr,
44
- esbuildOptions
10
+ unstable_mode: mode = 'emitCss'
45
11
  } = {}) {
46
12
  let config;
13
+ let userConfig;
47
14
  let server;
48
- let postCssConfig;
49
- // We lazily load this utility from Vite
50
- let normalizePath;
51
- const cssMap = new Map();
52
- const hasEmitCssOverride = typeof emitCssInSsr === 'boolean';
53
- let resolvedEmitCssInSsr = hasEmitCssOverride ? emitCssInSsr : !!process.env.VITE_RSC_BUILD;
54
15
  let packageName;
55
- const getAbsoluteVirtualFileId = source => normalizePath(path.join(config.root, source));
16
+ let compiler;
17
+ const getIdentOption = () => identifiers ?? (config.mode === 'production' ? 'short' : 'debug');
18
+ const getAbsoluteId = filePath => {
19
+ let resolvedId = filePath;
20
+ if (filePath.startsWith(config.root) ||
21
+ // In monorepos the absolute path will be outside of config.root, so we check that they have the same root on the file system
22
+ path.isAbsolute(filePath) && filePath.split(path.sep)[1] === config.root.split(path.sep)[1]) {
23
+ resolvedId = filePath;
24
+ } else {
25
+ // In SSR mode we can have paths like /app/styles.css.ts
26
+ resolvedId = path.join(config.root, filePath);
27
+ }
28
+ return normalizePath(resolvedId);
29
+ };
30
+ function invalidateModule(absoluteId) {
31
+ if (!server) return;
32
+ const {
33
+ moduleGraph
34
+ } = server;
35
+ const modules = moduleGraph.getModulesByFile(absoluteId);
36
+ if (modules) {
37
+ for (const module of modules) {
38
+ moduleGraph.invalidateModule(module);
39
+
40
+ // Vite uses this timestamp to add `?t=` query string automatically for HMR.
41
+ module.lastHMRTimestamp = module.lastInvalidationTimestamp || Date.now();
42
+ }
43
+ }
44
+ }
45
+ function addWatchFiles(fromId, files) {
46
+ // We don't need to watch files in build mode
47
+ if (config.command === 'build' && !config.build.watch) {
48
+ return;
49
+ }
50
+ for (const file of files) {
51
+ if (!file.includes('node_modules') && normalizePath(file) !== fromId) {
52
+ this.addWatchFile(file);
53
+ }
54
+ }
55
+ }
56
56
  return {
57
57
  name: 'vanilla-extract',
58
- enforce: 'pre',
59
58
  configureServer(_server) {
60
59
  server = _server;
61
60
  },
62
- config(_userConfig, env) {
63
- const include = env.command === 'serve' ? ['@vanilla-extract/css/injectStyles'] : [];
61
+ config(viteUserConfig) {
62
+ userConfig = viteUserConfig;
64
63
  return {
65
- optimizeDeps: {
66
- include
67
- },
68
64
  ssr: {
69
65
  external: ['@vanilla-extract/css', '@vanilla-extract/css/fileScope', '@vanilla-extract/css/adapter']
70
66
  }
@@ -73,76 +69,32 @@ function vanillaExtractPlugin({
73
69
  async configResolved(resolvedConfig) {
74
70
  config = resolvedConfig;
75
71
  packageName = getPackageInfo(config.root).name;
76
- normalizePath = (await import('vite')).normalizePath;
77
- if (config.command === 'serve') {
78
- postCssConfig = await resolvePostcssConfig(config);
79
- }
80
- if (!hasEmitCssOverride && config.plugins.some(plugin => ['astro:build', 'remix', 'solid-start-server', 'vite-plugin-qwik', 'vite-plugin-svelte'].includes(plugin.name))) {
81
- resolvedEmitCssInSsr = true;
72
+ if (mode !== 'transform') {
73
+ var _userConfig$plugins;
74
+ compiler = createCompiler({
75
+ root: config.root,
76
+ identifiers: getIdentOption(),
77
+ cssImportSpecifier: fileIdToVirtualId,
78
+ vitePlugins: (_userConfig$plugins = userConfig.plugins) === null || _userConfig$plugins === void 0 ? void 0 : _userConfig$plugins.flat().filter(plugin => typeof plugin === 'object' && plugin !== null && 'name' in plugin &&
79
+ // Prevent an infinite loop where the compiler creates a new instance of the plugin,
80
+ // which creates a new compiler, which creates a new instance of the plugin, etc.
81
+ plugin.name !== 'vanilla-extract' &&
82
+ // Skip Vitest plugins
83
+ plugin.name !== 'vitest' && !plugin.name.startsWith('vitest:'))
84
+ });
82
85
  }
83
86
  },
84
- resolveId(source) {
85
- const [validId, query] = source.split('?');
86
- if (!validId.endsWith(virtualExtCss) && !validId.endsWith(virtualExtJs)) {
87
- return;
88
- }
89
-
90
- // Absolute paths seem to occur often in monorepos, where files are
91
- // imported from outside the config root.
92
- const absoluteId = source.startsWith(config.root) ? source : getAbsoluteVirtualFileId(validId);
93
-
94
- // There should always be an entry in the `cssMap` here.
95
- // The only valid scenario for a missing one is if someone had written
96
- // a file in their app using the .vanilla.js/.vanilla.css extension
97
- if (cssMap.has(absoluteId)) {
98
- // Keep the original query string for HMR.
99
- return absoluteId + (query ? `?${query}` : '');
100
- }
87
+ buildEnd() {
88
+ var _compiler;
89
+ (_compiler = compiler) === null || _compiler === void 0 ? void 0 : _compiler.close();
101
90
  },
102
- load(id) {
103
- const [validId] = id.split('?');
104
- if (!cssMap.has(validId)) {
105
- return;
106
- }
107
- const css = cssMap.get(validId);
108
- if (typeof css !== 'string') {
109
- return;
110
- }
111
- if (validId.endsWith(virtualExtCss)) {
112
- return css;
113
- }
114
- return outdent`
115
- import { injectStyles } from '@vanilla-extract/css/injectStyles';
116
-
117
- const inject = (css) => injectStyles({
118
- fileScope: ${JSON.stringify({
119
- filePath: validId
120
- })},
121
- css
122
- });
123
-
124
- inject(${JSON.stringify(css)});
125
-
126
- if (import.meta.hot) {
127
- import.meta.hot.on('${styleUpdateEvent(validId)}', (css) => {
128
- inject(css);
129
- });
130
- }
131
- `;
132
- },
133
- async transform(code, id, ssrParam) {
91
+ async transform(code, id) {
134
92
  const [validId] = id.split('?');
135
93
  if (!cssFileFilter.test(validId)) {
136
94
  return null;
137
95
  }
138
- const identOption = identifiers ?? (config.mode === 'production' ? 'short' : 'debug');
139
- let ssr;
140
- if (typeof ssrParam === 'boolean') {
141
- ssr = ssrParam;
142
- } else {
143
- ssr = ssrParam === null || ssrParam === void 0 ? void 0 : ssrParam.ssr;
144
- }
145
- if (ssr && !resolvedEmitCssInSsr) {
96
+ const identOption = getIdentOption();
97
+ if (mode === 'transform') {
146
98
  return transform({
147
99
  source: code,
148
100
  filePath: normalizePath(validId),
@@ -151,73 +103,47 @@ function vanillaExtractPlugin({
151
103
  identOption
152
104
  });
153
105
  }
154
- const {
155
- source,
156
- watchFiles
157
- } = await compile({
158
- filePath: validId,
159
- cwd: config.root,
160
- esbuildOptions,
161
- identOption
162
- });
163
- for (const file of watchFiles) {
164
- // In start mode, we need to prevent the file from rewatching itself.
165
- // If it's a `build --watch`, it needs to watch everything.
166
- if (config.command === 'build' || normalizePath(file) !== validId) {
167
- this.addWatchFile(file);
168
- }
169
- }
170
- const output = await processVanillaFile({
171
- source,
172
- filePath: validId,
173
- identOption,
174
- serializeVirtualCssPath: async ({
175
- fileScope,
176
- source
177
- }) => {
178
- const rootRelativeId = `${fileScope.filePath}${config.command === 'build' || ssr && resolvedEmitCssInSsr ? virtualExtCss : virtualExtJs}`;
179
- const absoluteId = getAbsoluteVirtualFileId(rootRelativeId);
180
- let cssSource = source;
181
- if (postCssConfig) {
182
- const postCssResult = await (await import('postcss')).default(postCssConfig.plugins).process(source, {
183
- ...postCssConfig.options,
184
- from: undefined,
185
- map: false
186
- });
187
- cssSource = postCssResult.css;
188
- }
189
- if (server && cssMap.has(absoluteId) && cssMap.get(absoluteId) !== cssSource) {
190
- const {
191
- moduleGraph
192
- } = server;
193
- const modules = Array.from(moduleGraph.getModulesByFile(absoluteId) || []);
194
- for (const module of modules) {
195
- if (module) {
196
- moduleGraph.invalidateModule(module);
106
+ if (compiler) {
107
+ const absoluteId = getAbsoluteId(validId);
108
+ const {
109
+ source,
110
+ watchFiles
111
+ } = await compiler.processVanillaFile(absoluteId, {
112
+ outputCss: true
113
+ });
114
+ addWatchFiles.call(this, absoluteId, watchFiles);
197
115
 
198
- // Vite uses this timestamp to add `?t=` query string automatically for HMR.
199
- module.lastHMRTimestamp = module.lastInvalidationTimestamp || Date.now();
200
- }
201
- }
202
- server.ws.send({
203
- type: 'custom',
204
- event: styleUpdateEvent(absoluteId),
205
- data: cssSource
206
- });
116
+ // We have to invalidate the virtual module, not the real one we just transformed
117
+ invalidateModule(fileIdToVirtualId(absoluteId));
118
+ return {
119
+ code: source,
120
+ map: {
121
+ mappings: ''
207
122
  }
208
- cssMap.set(absoluteId, cssSource);
209
-
210
- // We use the root relative id here to ensure file contents (content-hashes)
211
- // are consistent across build machines
212
- return `import "${rootRelativeId}";`;
213
- }
214
- });
215
- return {
216
- code: output,
217
- map: {
218
- mappings: ''
219
- }
220
- };
123
+ };
124
+ }
125
+ },
126
+ resolveId(source) {
127
+ var _compiler2;
128
+ const [validId, query] = source.split('?');
129
+ if (!isVirtualId(validId)) return;
130
+ const absoluteId = getAbsoluteId(validId);
131
+ if ( // We should always have CSS for a file here.
132
+ // The only valid scenario for a missing one is if someone had written
133
+ // a file in their app using the .vanilla.js/.vanilla.css extension
134
+ (_compiler2 = compiler) !== null && _compiler2 !== void 0 && _compiler2.getCssForFile(virtualIdToFileId(absoluteId))) {
135
+ // Keep the original query string for HMR.
136
+ return absoluteId + (query ? `?${query}` : '');
137
+ }
138
+ },
139
+ load(id) {
140
+ const [validId] = id.split('?');
141
+ if (!isVirtualId(validId) || !compiler) return;
142
+ const absoluteId = getAbsoluteId(validId);
143
+ const {
144
+ css
145
+ } = compiler.getCssForFile(virtualIdToFileId(absoluteId));
146
+ return css;
221
147
  }
222
148
  };
223
149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vanilla-extract/vite-plugin",
3
- "version": "3.9.5",
3
+ "version": "4.0.1",
4
4
  "description": "Zero-runtime Stylesheets-in-TypeScript",
5
5
  "main": "dist/vanilla-extract-vite-plugin.cjs.js",
6
6
  "module": "dist/vanilla-extract-vite-plugin.esm.js",
@@ -15,15 +15,12 @@
15
15
  "author": "SEEK",
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
- "@vanilla-extract/integration": "^6.3.0",
19
- "outdent": "^0.8.0",
20
- "postcss": "^8.3.6",
21
- "postcss-load-config": "^4.0.1"
18
+ "@vanilla-extract/integration": "^6.4.0"
22
19
  },
23
20
  "devDependencies": {
24
- "vite": "npm:vite@^2.7.0"
21
+ "vite": "npm:vite@^5.0.11"
25
22
  },
26
23
  "peerDependencies": {
27
- "vite": "^2.2.3 || ^3.0.0 || ^4.0.3 || ^5.0.0"
24
+ "vite": "^4.0.3 || ^5.0.0"
28
25
  }
29
26
  }