@vanilla-extract/vite-plugin 2.1.2 → 3.1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 SEEK
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -82,7 +82,6 @@ Want to work at a higher level while maximising style re-use? Check out 🍨 [S
82
82
  - [webpack](#webpack)
83
83
  - [esbuild](#esbuild)
84
84
  - [Vite](#vite)
85
- - [Snowpack](#snowpack)
86
85
  - [Next.js](#nextjs)
87
86
  - [Gatsby](#gatsby)
88
87
  - [Test environments](#test-environments)
@@ -95,6 +94,7 @@ Want to work at a higher level while maximising style re-use? Check out 🍨 [S
95
94
  - [createTheme](#createtheme)
96
95
  - [createGlobalTheme](#createglobaltheme)
97
96
  - [createThemeContract](#createthemecontract)
97
+ - [createGlobalThemeContract](#createglobalthemecontract)
98
98
  - [assignVars](#assignvars)
99
99
  - [createVar](#createvar)
100
100
  - [fallbackVar](#fallbackvar)
@@ -271,27 +271,6 @@ export default {
271
271
 
272
272
  > Please note: There are currently no automatic readable class names during development. However, you can still manually provide a debug ID as the last argument to functions that generate scoped styles, e.g. `export const className = style({ ... }, 'className');`
273
273
 
274
- ### Snowpack
275
-
276
- 1. Install the dependencies.
277
-
278
- ```bash
279
- npm install @vanilla-extract/css @vanilla-extract/snowpack-plugin
280
- ```
281
-
282
- 2. Add the [Snowpack](https://www.snowpack.dev/) plugin to your snowpack config.
283
-
284
- > 💡 This plugin accepts an optional [configuration object](#configuration).
285
-
286
- ```js
287
- // snowpack.config.json
288
- {
289
- "plugins": ["@vanilla-extract/snowpack-plugin"]
290
- }
291
- ```
292
-
293
- > Please note: There are currently no automatic readable class names during development. However, you can still manually provide a debug ID as the last argument to functions that generate scoped styles, e.g. `export const className = style({ ... }, 'className');`
294
-
295
274
  ### Next.js
296
275
 
297
276
  1. Install the dependencies.
@@ -300,16 +279,7 @@ npm install @vanilla-extract/css @vanilla-extract/snowpack-plugin
300
279
  npm install @vanilla-extract/css @vanilla-extract/babel-plugin @vanilla-extract/next-plugin
301
280
  ```
302
281
 
303
- 2. If you don't have a `.babelrc` file in the root of your project, create one. Add the [Babel](https://babeljs.io) plugin to your `.babelrc` file, ensuring that you're also including `"next/babel"` in your `presets` array.
304
-
305
- ```json
306
- {
307
- "presets": ["next/babel"],
308
- "plugins": ["@vanilla-extract/babel-plugin"]
309
- }
310
- ```
311
-
312
- 3. If you don't have a `next.config.js` file in the root of your project, create one. Add the [Next.js](https://nextjs.org) plugin to your `next.config.js` file.
282
+ 2. If you don't have a `next.config.js` file in the root of your project, create one. Add the [Next.js](https://nextjs.org) plugin to your `next.config.js` file.
313
283
 
314
284
  > 💡 This plugin accepts an optional [configuration object](#configuration).
315
285
 
@@ -319,6 +289,7 @@ const {
319
289
  } = require('@vanilla-extract/next-plugin');
320
290
  const withVanillaExtract = createVanillaExtractPlugin();
321
291
 
292
+ /** @type {import('next').NextConfig} */
322
293
  const nextConfig = {};
323
294
 
324
295
  module.exports = withVanillaExtract(nextConfig);
@@ -336,11 +307,25 @@ const withMDX = require('@next/mdx')({
336
307
  extension: /\.mdx$/
337
308
  });
338
309
 
310
+ /** @type {import('next').NextConfig} */
339
311
  const nextConfig = {};
340
312
 
341
313
  module.exports = withVanillaExtract(withMDX(nextConfig));
342
314
  ```
343
315
 
316
+ 3. (Optional) If you want to automatically generate debug IDs during development, you can add the [Babel](https://babeljs.io) plugin. Note that this step will cause Next.js to switch from [SWC](https://github.com/swc-project/swc) to Babel, increasing build times. This may or may not be an issue depending on the size of your project.
317
+
318
+ > Note: While optional for Next.js, the Babel plugin is still required when trying to run `.css.ts` files in Node for unit testing since the files are no longer being processed by a bundler.
319
+
320
+ If you don't have a `.babelrc` file in the root of your project, create one. Add the Babel plugin to your `.babelrc` file, ensuring that you're also including `"next/babel"` in your `presets` array.
321
+
322
+ ```json
323
+ {
324
+ "presets": ["next/babel"],
325
+ "plugins": ["@vanilla-extract/babel-plugin"]
326
+ }
327
+ ```
328
+
344
329
  ### Gatsby
345
330
 
346
331
  To add to your [Gatsby](https://www.gatsbyjs.com) site, use the [gatsby-plugin-vanilla-extract](https://github.com/KyleAMathews/gatsby-plugin-vanilla-extract) plugin.
@@ -1,12 +1,7 @@
1
- import type { Plugin } from 'vite';
2
- import { IdentifierOption } from '@vanilla-extract/integration';
3
- interface Options {
4
- identifiers?: IdentifierOption;
5
- /**
6
- * Which CSS runtime to use when running `vite serve`.
7
- * @default 'vite'
8
- */
9
- devStyleRuntime?: 'vite' | 'vanilla-extract';
10
- }
11
- export declare function vanillaExtractPlugin({ identifiers, devStyleRuntime, }?: Options): Plugin;
12
- export {};
1
+ import type { Plugin } from 'vite';
2
+ import { IdentifierOption } from '@vanilla-extract/integration';
3
+ interface Options {
4
+ identifiers?: IdentifierOption;
5
+ }
6
+ export declare function vanillaExtractPlugin({ identifiers }?: Options): Plugin;
7
+ export {};
@@ -0,0 +1,7 @@
1
+ import type { ResolvedConfig } from 'vite';
2
+ import type { ProcessOptions, Plugin } from 'postcss';
3
+ export interface PostCSSConfigResult {
4
+ options: ProcessOptions;
5
+ plugins: Plugin[];
6
+ }
7
+ export declare const resolvePostcssConfig: (config: ResolvedConfig) => Promise<PostCSSConfigResult | null>;
@@ -4,49 +4,144 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var path = require('path');
6
6
  var vite = require('vite');
7
+ var outdent = require('outdent');
7
8
  var integration = require('@vanilla-extract/integration');
8
9
 
9
10
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
10
11
 
12
+ function _interopNamespace(e) {
13
+ if (e && e.__esModule) return e;
14
+ var n = Object.create(null);
15
+ if (e) {
16
+ Object.keys(e).forEach(function (k) {
17
+ if (k !== 'default') {
18
+ var d = Object.getOwnPropertyDescriptor(e, k);
19
+ Object.defineProperty(n, k, d.get ? d : {
20
+ enumerable: true,
21
+ get: function () { return e[k]; }
22
+ });
23
+ }
24
+ });
25
+ }
26
+ n["default"] = e;
27
+ return Object.freeze(n);
28
+ }
29
+
11
30
  var path__default = /*#__PURE__*/_interopDefault(path);
31
+ var outdent__default = /*#__PURE__*/_interopDefault(outdent);
32
+
33
+ // Mostly copied from vite's implementation
34
+ // https://github.com/vitejs/vite/blob/efec70f816b80e55b64255b32a5f120e1cf4e4be/packages/vite/src/node/plugins/css.ts
35
+ const resolvePostcssConfig = async config => {
36
+ // inline postcss config via vite config
37
+ const inlineOptions = config.css?.postcss;
38
+ const inlineOptionsIsString = typeof inlineOptions === 'string';
39
+
40
+ if (inlineOptions && !inlineOptionsIsString) {
41
+ const options = { ...inlineOptions
42
+ };
43
+ delete options.plugins;
44
+ return {
45
+ options,
46
+ plugins: inlineOptions.plugins || []
47
+ };
48
+ } else {
49
+ try {
50
+ const searchPath = typeof inlineOptions === 'string' ? inlineOptions : config.root;
51
+ const postCssConfig = await (await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('postcss-load-config')); })).default({}, searchPath);
52
+ return {
53
+ options: postCssConfig.options,
54
+ // @ts-expect-error - The postcssrc options don't agree with real postcss, but it should be ok
55
+ plugins: postCssConfig.plugins
56
+ };
57
+ } catch (e) {
58
+ if (!/No PostCSS Config found/.test(e.message)) {
59
+ throw e;
60
+ }
12
61
 
62
+ return null;
63
+ }
64
+ }
65
+ };
66
+
67
+ const styleUpdateEvent = fileId => `vanilla-extract-style-update:${fileId}`;
68
+
69
+ const virtualPrefix = 'virtual:vanilla-extract:';
13
70
  function vanillaExtractPlugin({
14
- identifiers,
15
- devStyleRuntime = 'vite'
71
+ identifiers
16
72
  } = {}) {
17
73
  let config;
18
74
  let packageInfo;
19
- let useRuntime = false;
75
+ let server;
76
+ let postCssConfig;
20
77
  const cssMap = new Map();
78
+ let virtualExt;
21
79
  return {
22
80
  name: 'vanilla-extract',
23
81
  enforce: 'pre',
24
82
 
25
- configResolved(resolvedConfig) {
83
+ configureServer(_server) {
84
+ server = _server;
85
+ },
86
+
87
+ config(_userConfig, env) {
88
+ const include = env.command === 'serve' ? ['@vanilla-extract/css/injectStyles'] : [];
89
+ return {
90
+ optimizeDeps: {
91
+ include
92
+ },
93
+ ssr: {
94
+ external: ['@vanilla-extract/css', '@vanilla-extract/css/fileScope', '@vanilla-extract/css/adapter']
95
+ }
96
+ };
97
+ },
98
+
99
+ async configResolved(resolvedConfig) {
26
100
  config = resolvedConfig;
27
- useRuntime = devStyleRuntime === 'vanilla-extract' && config.command === 'serve';
101
+
102
+ if (config.command === 'serve') {
103
+ postCssConfig = await resolvePostcssConfig(config);
104
+ }
105
+
106
+ virtualExt = `.vanilla.${config.command === 'serve' ? 'js' : 'css'}`;
28
107
  packageInfo = integration.getPackageInfo(config.root);
29
108
  },
30
109
 
31
110
  resolveId(id) {
32
- if (integration.virtualCssFileFilter.test(id)) {
33
- const {
34
- fileName,
35
- source
36
- } = integration.getSourceFromVirtualCssFile(id); // resolveId shouldn't really cause a side-effect however custom module meta isn't currently working
37
- // This is a hack work around until https://github.com/vitejs/vite/issues/3240 is resolved
38
-
39
- const shortHashFileName = vite.normalizePath(`${fileName}?hash=${integration.hash(source)}`);
40
- cssMap.set(shortHashFileName, source);
41
- return shortHashFileName;
111
+ if (id.indexOf(virtualPrefix) === 0) {
112
+ return id;
42
113
  }
43
114
  },
44
115
 
45
116
  load(id) {
46
- if (cssMap.has(id)) {
47
- const css = cssMap.get(id);
48
- cssMap.delete(id);
49
- return css;
117
+ if (id.indexOf(virtualPrefix) === 0) {
118
+ const fileScopeId = id.slice(virtualPrefix.length, id.indexOf(virtualExt));
119
+
120
+ if (!cssMap.has(fileScopeId)) {
121
+ throw new Error(`Unable to locate ${fileScopeId} in the CSS map.`);
122
+ }
123
+
124
+ const css = cssMap.get(fileScopeId);
125
+
126
+ if (!server) {
127
+ return css;
128
+ }
129
+
130
+ const fileScope = integration.parseFileScope(fileScopeId);
131
+ return outdent__default["default"]`
132
+ import { injectStyles } from '@vanilla-extract/css/injectStyles';
133
+
134
+ const inject = (css) => injectStyles({
135
+ fileScope: ${JSON.stringify(fileScope)},
136
+ css
137
+ });
138
+
139
+ inject(${JSON.stringify(css)});
140
+
141
+ import.meta.hot.on('${styleUpdateEvent(fileScopeId)}', (css) => {
142
+ inject(css);
143
+ });
144
+ `;
50
145
  }
51
146
 
52
147
  return null;
@@ -57,13 +152,13 @@ function vanillaExtractPlugin({
57
152
  return null;
58
153
  }
59
154
 
60
- const usedIndex = id.indexOf('?used');
61
- const fixedId = usedIndex > 0 ? id.substring(0, usedIndex) : id;
155
+ const index = id.indexOf('?');
156
+ const validId = index === -1 ? id : id.substring(0, index);
62
157
 
63
- if (ssr || useRuntime) {
158
+ if (ssr) {
64
159
  return integration.addFileScope({
65
160
  source: code,
66
- filePath: vite.normalizePath(path__default['default'].relative(packageInfo.dirname, fixedId)),
161
+ filePath: vite.normalizePath(path__default["default"].relative(packageInfo.dirname, validId)),
67
162
  packageInfo
68
163
  }).source;
69
164
  }
@@ -72,19 +167,58 @@ function vanillaExtractPlugin({
72
167
  source,
73
168
  watchFiles
74
169
  } = await integration.compile({
75
- filePath: fixedId,
170
+ filePath: validId,
76
171
  cwd: config.root
77
172
  });
78
173
 
79
174
  for (const file of watchFiles) {
80
- this.addWatchFile(file);
175
+ // In start mode, we need to prevent the file from rewatching itself.
176
+ // If it's a `build --watch`, it needs to watch everything.
177
+ if (config.command === 'build' || file !== id) {
178
+ this.addWatchFile(file);
179
+ }
81
180
  }
82
181
 
83
182
  return integration.processVanillaFile({
84
183
  source,
85
- filePath: fixedId,
86
- outputCss: !ssr,
87
- identOption: identifiers !== null && identifiers !== void 0 ? identifiers : config.mode === 'production' ? 'short' : 'debug'
184
+ filePath: validId,
185
+ identOption: identifiers ?? (config.mode === 'production' ? 'short' : 'debug'),
186
+ serializeVirtualCssPath: async ({
187
+ fileScope,
188
+ source
189
+ }) => {
190
+ const fileId = integration.stringifyFileScope(fileScope);
191
+ const id = `${virtualPrefix}${fileId}${virtualExt}`;
192
+ let cssSource = source;
193
+
194
+ if (postCssConfig) {
195
+ const postCssResult = await (await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('postcss')); })).default(postCssConfig.plugins).process(source, { ...postCssConfig.options,
196
+ from: undefined,
197
+ map: false
198
+ });
199
+ cssSource = postCssResult.css;
200
+ }
201
+
202
+ if (server && cssMap.has(fileId) && cssMap.get(fileId) !== source) {
203
+ const {
204
+ moduleGraph
205
+ } = server;
206
+ const module = moduleGraph.getModuleById(id);
207
+
208
+ if (module) {
209
+ moduleGraph.invalidateModule(module);
210
+ }
211
+
212
+ server.ws.send({
213
+ type: 'custom',
214
+ event: styleUpdateEvent(fileId),
215
+ data: cssSource
216
+ });
217
+ }
218
+
219
+ cssMap.set(fileId, cssSource);
220
+ return `import "${id}";`;
221
+ }
88
222
  });
89
223
  }
90
224
 
@@ -4,49 +4,144 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var path = require('path');
6
6
  var vite = require('vite');
7
+ var outdent = require('outdent');
7
8
  var integration = require('@vanilla-extract/integration');
8
9
 
9
10
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
10
11
 
12
+ function _interopNamespace(e) {
13
+ if (e && e.__esModule) return e;
14
+ var n = Object.create(null);
15
+ if (e) {
16
+ Object.keys(e).forEach(function (k) {
17
+ if (k !== 'default') {
18
+ var d = Object.getOwnPropertyDescriptor(e, k);
19
+ Object.defineProperty(n, k, d.get ? d : {
20
+ enumerable: true,
21
+ get: function () { return e[k]; }
22
+ });
23
+ }
24
+ });
25
+ }
26
+ n["default"] = e;
27
+ return Object.freeze(n);
28
+ }
29
+
11
30
  var path__default = /*#__PURE__*/_interopDefault(path);
31
+ var outdent__default = /*#__PURE__*/_interopDefault(outdent);
32
+
33
+ // Mostly copied from vite's implementation
34
+ // https://github.com/vitejs/vite/blob/efec70f816b80e55b64255b32a5f120e1cf4e4be/packages/vite/src/node/plugins/css.ts
35
+ const resolvePostcssConfig = async config => {
36
+ // inline postcss config via vite config
37
+ const inlineOptions = config.css?.postcss;
38
+ const inlineOptionsIsString = typeof inlineOptions === 'string';
39
+
40
+ if (inlineOptions && !inlineOptionsIsString) {
41
+ const options = { ...inlineOptions
42
+ };
43
+ delete options.plugins;
44
+ return {
45
+ options,
46
+ plugins: inlineOptions.plugins || []
47
+ };
48
+ } else {
49
+ try {
50
+ const searchPath = typeof inlineOptions === 'string' ? inlineOptions : config.root;
51
+ const postCssConfig = await (await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('postcss-load-config')); })).default({}, searchPath);
52
+ return {
53
+ options: postCssConfig.options,
54
+ // @ts-expect-error - The postcssrc options don't agree with real postcss, but it should be ok
55
+ plugins: postCssConfig.plugins
56
+ };
57
+ } catch (e) {
58
+ if (!/No PostCSS Config found/.test(e.message)) {
59
+ throw e;
60
+ }
12
61
 
62
+ return null;
63
+ }
64
+ }
65
+ };
66
+
67
+ const styleUpdateEvent = fileId => `vanilla-extract-style-update:${fileId}`;
68
+
69
+ const virtualPrefix = 'virtual:vanilla-extract:';
13
70
  function vanillaExtractPlugin({
14
- identifiers,
15
- devStyleRuntime = 'vite'
71
+ identifiers
16
72
  } = {}) {
17
73
  let config;
18
74
  let packageInfo;
19
- let useRuntime = false;
75
+ let server;
76
+ let postCssConfig;
20
77
  const cssMap = new Map();
78
+ let virtualExt;
21
79
  return {
22
80
  name: 'vanilla-extract',
23
81
  enforce: 'pre',
24
82
 
25
- configResolved(resolvedConfig) {
83
+ configureServer(_server) {
84
+ server = _server;
85
+ },
86
+
87
+ config(_userConfig, env) {
88
+ const include = env.command === 'serve' ? ['@vanilla-extract/css/injectStyles'] : [];
89
+ return {
90
+ optimizeDeps: {
91
+ include
92
+ },
93
+ ssr: {
94
+ external: ['@vanilla-extract/css', '@vanilla-extract/css/fileScope', '@vanilla-extract/css/adapter']
95
+ }
96
+ };
97
+ },
98
+
99
+ async configResolved(resolvedConfig) {
26
100
  config = resolvedConfig;
27
- useRuntime = devStyleRuntime === 'vanilla-extract' && config.command === 'serve';
101
+
102
+ if (config.command === 'serve') {
103
+ postCssConfig = await resolvePostcssConfig(config);
104
+ }
105
+
106
+ virtualExt = `.vanilla.${config.command === 'serve' ? 'js' : 'css'}`;
28
107
  packageInfo = integration.getPackageInfo(config.root);
29
108
  },
30
109
 
31
110
  resolveId(id) {
32
- if (integration.virtualCssFileFilter.test(id)) {
33
- const {
34
- fileName,
35
- source
36
- } = integration.getSourceFromVirtualCssFile(id); // resolveId shouldn't really cause a side-effect however custom module meta isn't currently working
37
- // This is a hack work around until https://github.com/vitejs/vite/issues/3240 is resolved
38
-
39
- const shortHashFileName = vite.normalizePath(`${fileName}?hash=${integration.hash(source)}`);
40
- cssMap.set(shortHashFileName, source);
41
- return shortHashFileName;
111
+ if (id.indexOf(virtualPrefix) === 0) {
112
+ return id;
42
113
  }
43
114
  },
44
115
 
45
116
  load(id) {
46
- if (cssMap.has(id)) {
47
- const css = cssMap.get(id);
48
- cssMap.delete(id);
49
- return css;
117
+ if (id.indexOf(virtualPrefix) === 0) {
118
+ const fileScopeId = id.slice(virtualPrefix.length, id.indexOf(virtualExt));
119
+
120
+ if (!cssMap.has(fileScopeId)) {
121
+ throw new Error(`Unable to locate ${fileScopeId} in the CSS map.`);
122
+ }
123
+
124
+ const css = cssMap.get(fileScopeId);
125
+
126
+ if (!server) {
127
+ return css;
128
+ }
129
+
130
+ const fileScope = integration.parseFileScope(fileScopeId);
131
+ return outdent__default["default"]`
132
+ import { injectStyles } from '@vanilla-extract/css/injectStyles';
133
+
134
+ const inject = (css) => injectStyles({
135
+ fileScope: ${JSON.stringify(fileScope)},
136
+ css
137
+ });
138
+
139
+ inject(${JSON.stringify(css)});
140
+
141
+ import.meta.hot.on('${styleUpdateEvent(fileScopeId)}', (css) => {
142
+ inject(css);
143
+ });
144
+ `;
50
145
  }
51
146
 
52
147
  return null;
@@ -57,13 +152,13 @@ function vanillaExtractPlugin({
57
152
  return null;
58
153
  }
59
154
 
60
- const usedIndex = id.indexOf('?used');
61
- const fixedId = usedIndex > 0 ? id.substring(0, usedIndex) : id;
155
+ const index = id.indexOf('?');
156
+ const validId = index === -1 ? id : id.substring(0, index);
62
157
 
63
- if (ssr || useRuntime) {
158
+ if (ssr) {
64
159
  return integration.addFileScope({
65
160
  source: code,
66
- filePath: vite.normalizePath(path__default['default'].relative(packageInfo.dirname, fixedId)),
161
+ filePath: vite.normalizePath(path__default["default"].relative(packageInfo.dirname, validId)),
67
162
  packageInfo
68
163
  }).source;
69
164
  }
@@ -72,19 +167,58 @@ function vanillaExtractPlugin({
72
167
  source,
73
168
  watchFiles
74
169
  } = await integration.compile({
75
- filePath: fixedId,
170
+ filePath: validId,
76
171
  cwd: config.root
77
172
  });
78
173
 
79
174
  for (const file of watchFiles) {
80
- this.addWatchFile(file);
175
+ // In start mode, we need to prevent the file from rewatching itself.
176
+ // If it's a `build --watch`, it needs to watch everything.
177
+ if (config.command === 'build' || file !== id) {
178
+ this.addWatchFile(file);
179
+ }
81
180
  }
82
181
 
83
182
  return integration.processVanillaFile({
84
183
  source,
85
- filePath: fixedId,
86
- outputCss: !ssr,
87
- identOption: identifiers !== null && identifiers !== void 0 ? identifiers : config.mode === 'production' ? 'short' : 'debug'
184
+ filePath: validId,
185
+ identOption: identifiers ?? (config.mode === 'production' ? 'short' : 'debug'),
186
+ serializeVirtualCssPath: async ({
187
+ fileScope,
188
+ source
189
+ }) => {
190
+ const fileId = integration.stringifyFileScope(fileScope);
191
+ const id = `${virtualPrefix}${fileId}${virtualExt}`;
192
+ let cssSource = source;
193
+
194
+ if (postCssConfig) {
195
+ const postCssResult = await (await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('postcss')); })).default(postCssConfig.plugins).process(source, { ...postCssConfig.options,
196
+ from: undefined,
197
+ map: false
198
+ });
199
+ cssSource = postCssResult.css;
200
+ }
201
+
202
+ if (server && cssMap.has(fileId) && cssMap.get(fileId) !== source) {
203
+ const {
204
+ moduleGraph
205
+ } = server;
206
+ const module = moduleGraph.getModuleById(id);
207
+
208
+ if (module) {
209
+ moduleGraph.invalidateModule(module);
210
+ }
211
+
212
+ server.ws.send({
213
+ type: 'custom',
214
+ event: styleUpdateEvent(fileId),
215
+ data: cssSource
216
+ });
217
+ }
218
+
219
+ cssMap.set(fileId, cssSource);
220
+ return `import "${id}";`;
221
+ }
88
222
  });
89
223
  }
90
224
 
@@ -1,44 +1,120 @@
1
1
  import path from 'path';
2
2
  import { normalizePath } from 'vite';
3
- import { getPackageInfo, virtualCssFileFilter, getSourceFromVirtualCssFile, hash, cssFileFilter, addFileScope, compile, processVanillaFile } from '@vanilla-extract/integration';
3
+ import outdent from 'outdent';
4
+ import { getPackageInfo, parseFileScope, cssFileFilter, addFileScope, compile, processVanillaFile, stringifyFileScope } from '@vanilla-extract/integration';
4
5
 
6
+ // Mostly copied from vite's implementation
7
+ // https://github.com/vitejs/vite/blob/efec70f816b80e55b64255b32a5f120e1cf4e4be/packages/vite/src/node/plugins/css.ts
8
+ const resolvePostcssConfig = async config => {
9
+ // inline postcss config via vite config
10
+ const inlineOptions = config.css?.postcss;
11
+ const inlineOptionsIsString = typeof inlineOptions === 'string';
12
+
13
+ if (inlineOptions && !inlineOptionsIsString) {
14
+ const options = { ...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
+ // @ts-expect-error - The postcssrc options don't agree with real postcss, but it should be ok
28
+ plugins: postCssConfig.plugins
29
+ };
30
+ } catch (e) {
31
+ if (!/No PostCSS Config found/.test(e.message)) {
32
+ throw e;
33
+ }
34
+
35
+ return null;
36
+ }
37
+ }
38
+ };
39
+
40
+ const styleUpdateEvent = fileId => `vanilla-extract-style-update:${fileId}`;
41
+
42
+ const virtualPrefix = 'virtual:vanilla-extract:';
5
43
  function vanillaExtractPlugin({
6
- identifiers,
7
- devStyleRuntime = 'vite'
44
+ identifiers
8
45
  } = {}) {
9
46
  let config;
10
47
  let packageInfo;
11
- let useRuntime = false;
48
+ let server;
49
+ let postCssConfig;
12
50
  const cssMap = new Map();
51
+ let virtualExt;
13
52
  return {
14
53
  name: 'vanilla-extract',
15
54
  enforce: 'pre',
16
55
 
17
- configResolved(resolvedConfig) {
56
+ configureServer(_server) {
57
+ server = _server;
58
+ },
59
+
60
+ config(_userConfig, env) {
61
+ const include = env.command === 'serve' ? ['@vanilla-extract/css/injectStyles'] : [];
62
+ return {
63
+ optimizeDeps: {
64
+ include
65
+ },
66
+ ssr: {
67
+ external: ['@vanilla-extract/css', '@vanilla-extract/css/fileScope', '@vanilla-extract/css/adapter']
68
+ }
69
+ };
70
+ },
71
+
72
+ async configResolved(resolvedConfig) {
18
73
  config = resolvedConfig;
19
- useRuntime = devStyleRuntime === 'vanilla-extract' && config.command === 'serve';
74
+
75
+ if (config.command === 'serve') {
76
+ postCssConfig = await resolvePostcssConfig(config);
77
+ }
78
+
79
+ virtualExt = `.vanilla.${config.command === 'serve' ? 'js' : 'css'}`;
20
80
  packageInfo = getPackageInfo(config.root);
21
81
  },
22
82
 
23
83
  resolveId(id) {
24
- if (virtualCssFileFilter.test(id)) {
25
- const {
26
- fileName,
27
- source
28
- } = getSourceFromVirtualCssFile(id); // resolveId shouldn't really cause a side-effect however custom module meta isn't currently working
29
- // This is a hack work around until https://github.com/vitejs/vite/issues/3240 is resolved
30
-
31
- const shortHashFileName = normalizePath(`${fileName}?hash=${hash(source)}`);
32
- cssMap.set(shortHashFileName, source);
33
- return shortHashFileName;
84
+ if (id.indexOf(virtualPrefix) === 0) {
85
+ return id;
34
86
  }
35
87
  },
36
88
 
37
89
  load(id) {
38
- if (cssMap.has(id)) {
39
- const css = cssMap.get(id);
40
- cssMap.delete(id);
41
- return css;
90
+ if (id.indexOf(virtualPrefix) === 0) {
91
+ const fileScopeId = id.slice(virtualPrefix.length, id.indexOf(virtualExt));
92
+
93
+ if (!cssMap.has(fileScopeId)) {
94
+ throw new Error(`Unable to locate ${fileScopeId} in the CSS map.`);
95
+ }
96
+
97
+ const css = cssMap.get(fileScopeId);
98
+
99
+ if (!server) {
100
+ return css;
101
+ }
102
+
103
+ const fileScope = parseFileScope(fileScopeId);
104
+ return outdent`
105
+ import { injectStyles } from '@vanilla-extract/css/injectStyles';
106
+
107
+ const inject = (css) => injectStyles({
108
+ fileScope: ${JSON.stringify(fileScope)},
109
+ css
110
+ });
111
+
112
+ inject(${JSON.stringify(css)});
113
+
114
+ import.meta.hot.on('${styleUpdateEvent(fileScopeId)}', (css) => {
115
+ inject(css);
116
+ });
117
+ `;
42
118
  }
43
119
 
44
120
  return null;
@@ -49,13 +125,13 @@ function vanillaExtractPlugin({
49
125
  return null;
50
126
  }
51
127
 
52
- const usedIndex = id.indexOf('?used');
53
- const fixedId = usedIndex > 0 ? id.substring(0, usedIndex) : id;
128
+ const index = id.indexOf('?');
129
+ const validId = index === -1 ? id : id.substring(0, index);
54
130
 
55
- if (ssr || useRuntime) {
131
+ if (ssr) {
56
132
  return addFileScope({
57
133
  source: code,
58
- filePath: normalizePath(path.relative(packageInfo.dirname, fixedId)),
134
+ filePath: normalizePath(path.relative(packageInfo.dirname, validId)),
59
135
  packageInfo
60
136
  }).source;
61
137
  }
@@ -64,19 +140,58 @@ function vanillaExtractPlugin({
64
140
  source,
65
141
  watchFiles
66
142
  } = await compile({
67
- filePath: fixedId,
143
+ filePath: validId,
68
144
  cwd: config.root
69
145
  });
70
146
 
71
147
  for (const file of watchFiles) {
72
- this.addWatchFile(file);
148
+ // In start mode, we need to prevent the file from rewatching itself.
149
+ // If it's a `build --watch`, it needs to watch everything.
150
+ if (config.command === 'build' || file !== id) {
151
+ this.addWatchFile(file);
152
+ }
73
153
  }
74
154
 
75
155
  return processVanillaFile({
76
156
  source,
77
- filePath: fixedId,
78
- outputCss: !ssr,
79
- identOption: identifiers !== null && identifiers !== void 0 ? identifiers : config.mode === 'production' ? 'short' : 'debug'
157
+ filePath: validId,
158
+ identOption: identifiers ?? (config.mode === 'production' ? 'short' : 'debug'),
159
+ serializeVirtualCssPath: async ({
160
+ fileScope,
161
+ source
162
+ }) => {
163
+ const fileId = stringifyFileScope(fileScope);
164
+ const id = `${virtualPrefix}${fileId}${virtualExt}`;
165
+ let cssSource = source;
166
+
167
+ if (postCssConfig) {
168
+ const postCssResult = await (await import('postcss')).default(postCssConfig.plugins).process(source, { ...postCssConfig.options,
169
+ from: undefined,
170
+ map: false
171
+ });
172
+ cssSource = postCssResult.css;
173
+ }
174
+
175
+ if (server && cssMap.has(fileId) && cssMap.get(fileId) !== source) {
176
+ const {
177
+ moduleGraph
178
+ } = server;
179
+ const module = moduleGraph.getModuleById(id);
180
+
181
+ if (module) {
182
+ moduleGraph.invalidateModule(module);
183
+ }
184
+
185
+ server.ws.send({
186
+ type: 'custom',
187
+ event: styleUpdateEvent(fileId),
188
+ data: cssSource
189
+ });
190
+ }
191
+
192
+ cssMap.set(fileId, cssSource);
193
+ return `import "${id}";`;
194
+ }
80
195
  });
81
196
  }
82
197
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vanilla-extract/vite-plugin",
3
- "version": "2.1.2",
3
+ "version": "3.1.0",
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,7 +15,10 @@
15
15
  "author": "SEEK",
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
- "@vanilla-extract/integration": "^1.4.2"
18
+ "@vanilla-extract/integration": "^2.0.0",
19
+ "outdent": "^0.8.0",
20
+ "postcss": "^8.3.6",
21
+ "postcss-load-config": "^3.1.0"
19
22
  },
20
23
  "devDependencies": {
21
24
  "vite": "^2.6.0"
@@ -23,4 +26,4 @@
23
26
  "peerDependencies": {
24
27
  "vite": "^2.2.3"
25
28
  }
26
- }
29
+ }
package/CHANGELOG.md DELETED
@@ -1,141 +0,0 @@
1
- # @vanilla-extract/vite-plugin
2
-
3
- ## 2.1.2
4
-
5
- ### Patch Changes
6
-
7
- - [#398](https://github.com/seek-oss/vanilla-extract/pull/398) [`63f4ed0`](https://github.com/seek-oss/vanilla-extract/commit/63f4ed0e67419df565f3f447cf27cec612afbb8d) Thanks [@benjervis](https://github.com/benjervis)! - Fixes a bug with vite where "?used" is appended to the file path of css files.
8
-
9
- This could cause different class name hashes to be generated between SSR and client builds.
10
- This was introduced in vite 2.6.0.
11
-
12
- ## 2.1.1
13
-
14
- ### Patch Changes
15
-
16
- - [#393](https://github.com/seek-oss/vanilla-extract/pull/393) [`2f379f1`](https://github.com/seek-oss/vanilla-extract/commit/2f379f118c2a2fe6dc08a1cc15a395dbc0f17ece) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Fix compilation errors in Vite 2.6
17
-
18
- - Updated dependencies [[`2f379f1`](https://github.com/seek-oss/vanilla-extract/commit/2f379f118c2a2fe6dc08a1cc15a395dbc0f17ece)]:
19
- - @vanilla-extract/integration@1.4.2
20
-
21
- ## 2.1.0
22
-
23
- ### Minor Changes
24
-
25
- - [#373](https://github.com/seek-oss/vanilla-extract/pull/373) [`a55d2cf`](https://github.com/seek-oss/vanilla-extract/commit/a55d2cfd7c4ca9175a2c86557888df90907bfd0f) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Add `devStyleRuntime` option to allow switching between dev style runtimes
26
-
27
- The built-in Vite dev style runtime (what adds styles to the page when running `vite serve`) doesn't seem to clean up old styles as expected. Passing `devStyleRuntime: 'vanilla-extract'` will instead use vanilla-extract's browser runtime. This pushes all style creation in development to the browser, but may give a better HMR experience.
28
-
29
- ## 2.0.2
30
-
31
- ### Patch Changes
32
-
33
- - [#341](https://github.com/seek-oss/vanilla-extract/pull/341) [`0b743e7`](https://github.com/seek-oss/vanilla-extract/commit/0b743e744447616f8daf0c6b88beff8ffef8d41b) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Refactor SSR file scoping to use centralised `addFileScope` implementation
34
-
35
- - Updated dependencies [[`50bae14`](https://github.com/seek-oss/vanilla-extract/commit/50bae14bf38c8a971ad1727cb8e827c86da06772), [`0b743e7`](https://github.com/seek-oss/vanilla-extract/commit/0b743e744447616f8daf0c6b88beff8ffef8d41b)]:
36
- - @vanilla-extract/integration@1.3.0
37
-
38
- ## 2.0.1
39
-
40
- ### Patch Changes
41
-
42
- - [#327](https://github.com/seek-oss/vanilla-extract/pull/327) [`73b55f8`](https://github.com/seek-oss/vanilla-extract/commit/73b55f8e7e205701abdb1cbb029c3f2f5080b6fd) Thanks [@benjervis](https://github.com/benjervis)! - Fix bug where precompiled .css.ts files (.css.js) were treated differently in SSR mode.
43
-
44
- ## 2.0.0
45
-
46
- ### Major Changes
47
-
48
- - [#323](https://github.com/seek-oss/vanilla-extract/pull/323) [`1e7d647`](https://github.com/seek-oss/vanilla-extract/commit/1e7d6470398a0fbcbdef4118e678150932cd9275) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Formatting of identifiers (e.g. class names, keyframes, CSS Vars, etc) can now be configured via the `identifiers` option which accepts either `short` or `debug`.
49
-
50
- - `short` identifiers are a 7+ character hash. e.g. `hnw5tz3`
51
- - `debug` identifiers contain human readable prefixes representing the owning filename and a potential rule level debug name. e.g. `somefile_mystyle_hnw5tz3`
52
-
53
- ```js
54
- import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
55
-
56
- vanillaExtractPlugin({ identifiers: 'short' });
57
- ```
58
-
59
- BREAKING CHANGE
60
-
61
- Previously identifiers were formatted as `short` when `process.env.NODE_ENV` was set to "production". By default, they will now be formatted according to Vite's [mode config](https://vitejs.dev/config/#mode).
62
-
63
- ### Patch Changes
64
-
65
- - Updated dependencies [[`1e7d647`](https://github.com/seek-oss/vanilla-extract/commit/1e7d6470398a0fbcbdef4118e678150932cd9275)]:
66
- - @vanilla-extract/integration@1.2.0
67
-
68
- ## 1.2.0
69
-
70
- ### Minor Changes
71
-
72
- - [#311](https://github.com/seek-oss/vanilla-extract/pull/311) [`416eb9a`](https://github.com/seek-oss/vanilla-extract/commit/416eb9ae99661597a8443594f4376aacf4d295cc) Thanks [@mattcompiles](https://github.com/mattcompiles)! - In SSR mode, move to runtime evaluation of vanilla-extract files
73
-
74
- This unlocks the potential for CSS extraction on the server.
75
-
76
- ## 1.1.2
77
-
78
- ### Patch Changes
79
-
80
- - [#290](https://github.com/seek-oss/vanilla-extract/pull/290) [`adc1d64`](https://github.com/seek-oss/vanilla-extract/commit/adc1d644635a1197edd36f522f78658a641027d4) Thanks [@ygj6](https://github.com/ygj6)! - Normalize path of generated CSS files
81
-
82
- ## 1.1.1
83
-
84
- ### Patch Changes
85
-
86
- - [#270](https://github.com/seek-oss/vanilla-extract/pull/270) [`fe19158`](https://github.com/seek-oss/vanilla-extract/commit/fe1915808b374a1bbf8f67eca85c0253153e2cb9) Thanks [@yyx990803](https://github.com/yyx990803)! - Fix watching of modules imported by `.css.ts` files
87
-
88
- ## 1.1.0
89
-
90
- ### Minor Changes
91
-
92
- - [#259](https://github.com/seek-oss/vanilla-extract/pull/259) [`b8a6441`](https://github.com/seek-oss/vanilla-extract/commit/b8a6441e3400be388a520e3acf94f3bb6519cf0a) Thanks [@markdalgleish](https://github.com/markdalgleish)! - Allow the result of `composeStyles` to be used in selectors
93
-
94
- When style compositions are used in selectors, they are now assigned an additional class so they can be uniquely identified. When selectors are processed internally, the composed classes are removed, only leaving behind the unique identifier classes. This allows you to treat them as if they were a single class within vanilla-extract selectors.
95
-
96
- ```ts
97
- import { style, globalStyle, composeStyles } from '@vanilla-extract/css';
98
-
99
- const background = style({ background: 'mintcream' });
100
- const padding = style({ padding: 12 });
101
-
102
- export const container = composeStyles(background, padding);
103
-
104
- globalStyle(`${container} *`, {
105
- boxSizing: 'border-box',
106
- });
107
- ```
108
-
109
- ### Patch Changes
110
-
111
- - Updated dependencies [[`b8a6441`](https://github.com/seek-oss/vanilla-extract/commit/b8a6441e3400be388a520e3acf94f3bb6519cf0a)]:
112
- - @vanilla-extract/integration@1.1.0
113
-
114
- ## 1.0.0
115
-
116
- ### Major Changes
117
-
118
- - [#171](https://github.com/seek-oss/vanilla-extract/pull/171) [`84a8611`](https://github.com/seek-oss/vanilla-extract/commit/84a8611972f32a00a6cbd85267a01dd2d31be869) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Release v1
119
-
120
- ### Patch Changes
121
-
122
- - Updated dependencies [[`84a8611`](https://github.com/seek-oss/vanilla-extract/commit/84a8611972f32a00a6cbd85267a01dd2d31be869)]:
123
- - @vanilla-extract/integration@1.0.0
124
-
125
- ## 0.1.1
126
-
127
- ### Patch Changes
128
-
129
- - [#96](https://github.com/seek-oss/vanilla-extract/pull/96) [`697a233`](https://github.com/seek-oss/vanilla-extract/commit/697a2332cdb34886af26224c13f1efb73b6d36b3) Thanks [@mattcompiles](https://github.com/mattcompiles)! - Change vite-plugin to be a named export
130
-
131
- BREAKING CHANGE
132
-
133
- ```diff
134
- -import vanillaExtractPlugin from '@vanilla-extract/vite-plugin';
135
- +import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';
136
-
137
- // vite.config.js
138
- export default {
139
- plugins: [vanillaExtractPlugin()]
140
- }
141
- ```