@vanilla-extract/next-plugin 2.4.17 → 2.5.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,7 +1,18 @@
1
1
  import { VanillaExtractPlugin } from '@vanilla-extract/webpack-plugin/next';
2
2
  import { NextConfig } from 'next/dist/server/config-shared';
3
3
 
4
- type PluginOptions = ConstructorParameters<typeof VanillaExtractPlugin>[0];
4
+ type PluginOptions = ConstructorParameters<typeof VanillaExtractPlugin>[0] & {
5
+ unstable_turbopack?: {
6
+ glob?: string[];
7
+ /**
8
+ * controls whether we attempt to configure turbopack
9
+ * auto: enable only when Next >= 16.0.0
10
+ * on: force enable regardless of detected Next version
11
+ * off: never configure turbopack, webpack only
12
+ */
13
+ mode?: 'auto' | 'on' | 'off';
14
+ };
15
+ };
5
16
  declare const createVanillaExtractPlugin: (pluginOptions?: PluginOptions) => (nextConfig?: NextConfig) => NextConfig;
6
17
 
7
18
  export { createVanillaExtractPlugin };
@@ -9,11 +9,33 @@ var findPagesDir = require('next/dist/lib/find-pages-dir');
9
9
  var css = require('next/dist/build/webpack/config/blocks/css');
10
10
  var fileResolve = require('next/dist/build/webpack/config/blocks/css/loaders/file-resolve');
11
11
  var node_module = require('node:module');
12
+ var path = require('node:path');
13
+ var semver = require('semver');
12
14
 
13
15
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
14
16
 
17
+ function _interopNamespace(e) {
18
+ if (e && e.__esModule) return e;
19
+ var n = Object.create(null);
20
+ if (e) {
21
+ Object.keys(e).forEach(function (k) {
22
+ if (k !== 'default') {
23
+ var d = Object.getOwnPropertyDescriptor(e, k);
24
+ Object.defineProperty(n, k, d.get ? d : {
25
+ enumerable: true,
26
+ get: function () { return e[k]; }
27
+ });
28
+ }
29
+ });
30
+ }
31
+ n["default"] = e;
32
+ return Object.freeze(n);
33
+ }
34
+
15
35
  var browserslist__default = /*#__PURE__*/_interopDefault(browserslist);
16
36
  var NextMiniCssExtractPluginDefault__default = /*#__PURE__*/_interopDefault(NextMiniCssExtractPluginDefault);
37
+ var path__namespace = /*#__PURE__*/_interopNamespace(path);
38
+ var semver__default = /*#__PURE__*/_interopDefault(semver);
17
39
 
18
40
  // @ts-expect-error
19
41
  const require$1 = node_module.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('dist/vanilla-extract-next-plugin.cjs.dev.js', document.baseURI).href)));
@@ -113,77 +135,143 @@ const getVanillaExtractCssLoaders = (options, assetPrefix, hasAppDir) => {
113
135
  return loaders;
114
136
  };
115
137
  const createVanillaExtractPlugin = (pluginOptions = {}) => {
116
- return (nextConfig = {}) => ({
117
- ...nextConfig,
118
- webpack(config, options) {
119
- var _resolvedNextConfig$e;
120
- const {
121
- dir,
122
- dev,
123
- config: resolvedNextConfig
124
- } = options;
125
-
126
- // https://github.com/vercel/next.js/blob/1fb4cad2a8329811b5ccde47217b4a6ae739124e/packages/next/build/index.ts#L336
127
- // https://github.com/vercel/next.js/blob/1fb4cad2a8329811b5ccde47217b4a6ae739124e/packages/next/build/webpack-config.ts#L626
128
- // https://github.com/vercel/next.js/pull/43916
129
- // on Next.js 12, findPagesDirResult is a string. on Next.js 13, findPagesDirResult is an object
130
- const findPagesDirResult = findPagesDir.findPagesDir(dir, ((_resolvedNextConfig$e = resolvedNextConfig.experimental) === null || _resolvedNextConfig$e === void 0 ? void 0 : _resolvedNextConfig$e.appDir) ?? false);
131
- // Skip nextConfig check since appDir is stable feature after Next.js 13.4
132
- const hasAppDir = !!(findPagesDirResult && findPagesDirResult.appDir);
133
- const outputCss = true;
134
-
135
- // https://github.com/vercel/next.js/blob/6e5b935fd7a61497f6854a81aec7df3a5dbf61ac/packages/next/src/build/webpack/config/helpers.ts#L12-L21
136
- const cssRules = config.module.rules.find(rule => Array.isArray(rule.oneOf) && rule.oneOf.some(({
137
- test
138
- }) => typeof test === 'object' && typeof test.test === 'function' && test.test('filename.css'))).oneOf;
139
-
140
- // https://github.com/SukkaW/style9-webpack/blob/f51c46bbcd95ea3b988d3559c3b35cc056874366/src/next-appdir/index.ts#L187-L190
141
- cssRules.unshift({
142
- test: /vanilla\.virtual\.css/i,
143
- sideEffects: true,
144
- use: getVanillaExtractCssLoaders(options, resolvedNextConfig.assetPrefix, hasAppDir)
145
- });
138
+ return (nextConfig = {}) => {
139
+ const {
140
+ unstable_turbopack: turbopackOptions = {},
141
+ ...webpackPluginOptions
142
+ } = pluginOptions;
143
+ const {
144
+ mode: turbopackMode = 'off',
145
+ glob: turbopackGlob = ['**/*.css.{js,cjs,mjs,jsx,ts,tsx}']
146
+ } = turbopackOptions;
147
+ // detect Next version and decide whether to configure turbopack
148
+ const nextVersion = (() => {
149
+ try {
150
+ // resolve from the consumer app's cwd, not this package
151
+ const requireFromCwd = node_module.createRequire(path__namespace.join(process.cwd(), 'package.json'));
152
+ const pkg = requireFromCwd('next/package.json');
153
+ return (pkg === null || pkg === void 0 ? void 0 : pkg.version) ?? null;
154
+ } catch {
155
+ return null;
156
+ }
157
+ })();
158
+ const coerced = nextVersion ? semver__default["default"].coerce(nextVersion) : null;
159
+ const supportsTurbopackRules = !!coerced && semver__default["default"].gte(coerced, '16.0.0');
160
+ const enableTurbopack = turbopackMode === 'on' || turbopackMode === 'auto' && supportsTurbopackRules;
161
+ if (turbopackMode === 'on' && !supportsTurbopackRules) {
162
+ console.warn(`[@vanilla-extract/next-plugin] Turbopack is configured but does not seem supported. Expected Next.js >= 16.0.0, got ${nextVersion}`);
163
+ }
164
+ let turbopack;
165
+ if (enableTurbopack) {
166
+ turbopack = {
167
+ ...(nextConfig.turbopack || {})
168
+ };
169
+ if (turbopackGlob.some(glob => {
170
+ var _turbopack$rules;
171
+ return (_turbopack$rules = turbopack.rules) === null || _turbopack$rules === void 0 ? void 0 : _turbopack$rules[glob];
172
+ })) {
173
+ throw new Error('Vanilla extract could not be applied automatically due to conflicting turbopack rules');
174
+ }
175
+ const vanillaExtractRule = {
176
+ as: '*.js',
177
+ loaders: [{
178
+ loader: require$1.resolve('@vanilla-extract/turbopack-plugin'),
179
+ options: {
180
+ nextEnv: nextConfig.env ?? null,
181
+ outputCss: pluginOptions.outputCss ?? null,
182
+ identifiers: pluginOptions.identifiers ?? null
183
+ }
184
+ }]
185
+ };
186
+ const vanillaExtractCssRule = {
187
+ as: '*.css',
188
+ loaders: [require$1.resolve('@vanilla-extract/turbopack-plugin')]
189
+ };
190
+ turbopack.rules = {
191
+ ...(turbopack.rules || {}),
192
+ ...Object.fromEntries(turbopackGlob.map(glob => [glob, vanillaExtractRule])),
193
+ 'vanilla.virtual.css': vanillaExtractCssRule
194
+ };
195
+ }
196
+ const baseConfig = {
197
+ ...nextConfig,
198
+ webpack(config, options) {
199
+ var _resolvedNextConfig$e;
200
+ const {
201
+ dir,
202
+ dev,
203
+ config: resolvedNextConfig
204
+ } = options;
205
+
206
+ // https://github.com/vercel/next.js/blob/1fb4cad2a8329811b5ccde47217b4a6ae739124e/packages/next/build/index.ts#L336
207
+ // https://github.com/vercel/next.js/blob/1fb4cad2a8329811b5ccde47217b4a6ae739124e/packages/next/build/webpack-config.ts#L626
208
+ // https://github.com/vercel/next.js/pull/43916
209
+ // on Next.js 12, findPagesDirResult is a string. on Next.js 13, findPagesDirResult is an object
210
+ const findPagesDirResult = findPagesDir.findPagesDir(dir, ((_resolvedNextConfig$e = resolvedNextConfig.experimental) === null || _resolvedNextConfig$e === void 0 ? void 0 : _resolvedNextConfig$e.appDir) ?? false);
211
+ // Skip nextConfig check since appDir is stable feature after Next.js 13.4
212
+ const hasAppDir = !!(findPagesDirResult && findPagesDirResult.appDir);
213
+ const outputCss = true;
214
+
215
+ // https://github.com/vercel/next.js/blob/6e5b935fd7a61497f6854a81aec7df3a5dbf61ac/packages/next/src/build/webpack/config/helpers.ts#L12-L21
216
+ const cssRules = config.module.rules.find(rule => Array.isArray(rule.oneOf) && rule.oneOf.some(({
217
+ test
218
+ }) => typeof test === 'object' && typeof test.test === 'function' && test.test('filename.css'))).oneOf;
219
+
220
+ // https://github.com/SukkaW/style9-webpack/blob/f51c46bbcd95ea3b988d3559c3b35cc056874366/src/next-appdir/index.ts#L187-L190
221
+ cssRules.unshift({
222
+ test: /vanilla\.virtual\.css/i,
223
+ sideEffects: true,
224
+ use: getVanillaExtractCssLoaders(options, resolvedNextConfig.assetPrefix, hasAppDir)
225
+ });
146
226
 
147
- // vanilla-extract need to emit the css file on both server and client, both during the
148
- // development and production.
149
- // However, Next.js only add MiniCssExtractPlugin on pages dir + client build + production mode.
150
- //
151
- // To simplify the logic at our side, we will add MiniCssExtractPlugin based on
152
- // the "instanceof" check (We will only add our required MiniCssExtractPlugin if
153
- // Next.js hasn't added it yet).
154
- // This also prevent multiple MiniCssExtractPlugin being added (which will cause
155
- // RealContentHashPlugin to panic)
156
- if (!config.plugins.some(p => p instanceof NextMiniCssExtractPlugin)) {
157
- // HMR reloads the CSS file when the content changes but does not use
158
- // the new file name, which means it can't contain a hash.
159
- const filename = dev ? 'static/css/[name].css' : 'static/css/[contenthash].css';
160
- config.plugins.push(new NextMiniCssExtractPlugin({
161
- filename,
162
- chunkFilename: filename,
163
- // Next.js guarantees that CSS order "doesn't matter", due to imposed
164
- // restrictions:
165
- // 1. Global CSS can only be defined in a single entrypoint (_app)
166
- // 2. CSS Modules generate scoped class names by default and cannot
167
- // include Global CSS (:global() selector).
168
- //
169
- // While not a perfect guarantee (e.g. liberal use of `:global()`
170
- // selector), this assumption is required to code-split CSS.
171
- //
172
- // If this warning were to trigger, it'd be unactionable by the user,
173
- // but likely not valid -- so just disable it.
174
- ignoreOrder: true
227
+ // vanilla-extract need to emit the css file on both server and client, both during the
228
+ // development and production.
229
+ // However, Next.js only add MiniCssExtractPlugin on pages dir + client build + production mode.
230
+ //
231
+ // To simplify the logic at our side, we will add MiniCssExtractPlugin based on
232
+ // the "instanceof" check (We will only add our required MiniCssExtractPlugin if
233
+ // Next.js hasn't added it yet).
234
+ // This also prevent multiple MiniCssExtractPlugin being added (which will cause
235
+ // RealContentHashPlugin to panic)
236
+ if (!config.plugins.some(p => p instanceof NextMiniCssExtractPlugin)) {
237
+ // HMR reloads the CSS file when the content changes but does not use
238
+ // the new file name, which means it can't contain a hash.
239
+ const filename = dev ? 'static/css/[name].css' : 'static/css/[contenthash].css';
240
+ config.plugins.push(new NextMiniCssExtractPlugin({
241
+ filename,
242
+ chunkFilename: filename,
243
+ // Next.js guarantees that CSS order "doesn't matter", due to imposed
244
+ // restrictions:
245
+ // 1. Global CSS can only be defined in a single entrypoint (_app)
246
+ // 2. CSS Modules generate scoped class names by default and cannot
247
+ // include Global CSS (:global() selector).
248
+ //
249
+ // While not a perfect guarantee (e.g. liberal use of `:global()`
250
+ // selector), this assumption is required to code-split CSS.
251
+ //
252
+ // If this warning were to trigger, it'd be unactionable by the user,
253
+ // but likely not valid -- so just disable it.
254
+ ignoreOrder: true
255
+ }));
256
+ }
257
+ config.plugins.push(new next.VanillaExtractPlugin({
258
+ outputCss,
259
+ ...webpackPluginOptions
175
260
  }));
261
+ if (typeof nextConfig.webpack === 'function') {
262
+ return nextConfig.webpack(config, options);
263
+ }
264
+ return config;
176
265
  }
177
- config.plugins.push(new next.VanillaExtractPlugin({
178
- outputCss,
179
- ...pluginOptions
180
- }));
181
- if (typeof nextConfig.webpack === 'function') {
182
- return nextConfig.webpack(config, options);
183
- }
184
- return config;
266
+ };
267
+ if (enableTurbopack && turbopack) {
268
+ return {
269
+ ...baseConfig,
270
+ turbopack
271
+ };
185
272
  }
186
- });
273
+ return baseConfig;
274
+ };
187
275
  };
188
276
 
189
277
  exports.createVanillaExtractPlugin = createVanillaExtractPlugin;
@@ -9,11 +9,33 @@ var findPagesDir = require('next/dist/lib/find-pages-dir');
9
9
  var css = require('next/dist/build/webpack/config/blocks/css');
10
10
  var fileResolve = require('next/dist/build/webpack/config/blocks/css/loaders/file-resolve');
11
11
  var node_module = require('node:module');
12
+ var path = require('node:path');
13
+ var semver = require('semver');
12
14
 
13
15
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
14
16
 
17
+ function _interopNamespace(e) {
18
+ if (e && e.__esModule) return e;
19
+ var n = Object.create(null);
20
+ if (e) {
21
+ Object.keys(e).forEach(function (k) {
22
+ if (k !== 'default') {
23
+ var d = Object.getOwnPropertyDescriptor(e, k);
24
+ Object.defineProperty(n, k, d.get ? d : {
25
+ enumerable: true,
26
+ get: function () { return e[k]; }
27
+ });
28
+ }
29
+ });
30
+ }
31
+ n["default"] = e;
32
+ return Object.freeze(n);
33
+ }
34
+
15
35
  var browserslist__default = /*#__PURE__*/_interopDefault(browserslist);
16
36
  var NextMiniCssExtractPluginDefault__default = /*#__PURE__*/_interopDefault(NextMiniCssExtractPluginDefault);
37
+ var path__namespace = /*#__PURE__*/_interopNamespace(path);
38
+ var semver__default = /*#__PURE__*/_interopDefault(semver);
17
39
 
18
40
  // @ts-expect-error
19
41
  const require$1 = node_module.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('dist/vanilla-extract-next-plugin.cjs.prod.js', document.baseURI).href)));
@@ -113,77 +135,143 @@ const getVanillaExtractCssLoaders = (options, assetPrefix, hasAppDir) => {
113
135
  return loaders;
114
136
  };
115
137
  const createVanillaExtractPlugin = (pluginOptions = {}) => {
116
- return (nextConfig = {}) => ({
117
- ...nextConfig,
118
- webpack(config, options) {
119
- var _resolvedNextConfig$e;
120
- const {
121
- dir,
122
- dev,
123
- config: resolvedNextConfig
124
- } = options;
125
-
126
- // https://github.com/vercel/next.js/blob/1fb4cad2a8329811b5ccde47217b4a6ae739124e/packages/next/build/index.ts#L336
127
- // https://github.com/vercel/next.js/blob/1fb4cad2a8329811b5ccde47217b4a6ae739124e/packages/next/build/webpack-config.ts#L626
128
- // https://github.com/vercel/next.js/pull/43916
129
- // on Next.js 12, findPagesDirResult is a string. on Next.js 13, findPagesDirResult is an object
130
- const findPagesDirResult = findPagesDir.findPagesDir(dir, ((_resolvedNextConfig$e = resolvedNextConfig.experimental) === null || _resolvedNextConfig$e === void 0 ? void 0 : _resolvedNextConfig$e.appDir) ?? false);
131
- // Skip nextConfig check since appDir is stable feature after Next.js 13.4
132
- const hasAppDir = !!(findPagesDirResult && findPagesDirResult.appDir);
133
- const outputCss = true;
134
-
135
- // https://github.com/vercel/next.js/blob/6e5b935fd7a61497f6854a81aec7df3a5dbf61ac/packages/next/src/build/webpack/config/helpers.ts#L12-L21
136
- const cssRules = config.module.rules.find(rule => Array.isArray(rule.oneOf) && rule.oneOf.some(({
137
- test
138
- }) => typeof test === 'object' && typeof test.test === 'function' && test.test('filename.css'))).oneOf;
139
-
140
- // https://github.com/SukkaW/style9-webpack/blob/f51c46bbcd95ea3b988d3559c3b35cc056874366/src/next-appdir/index.ts#L187-L190
141
- cssRules.unshift({
142
- test: /vanilla\.virtual\.css/i,
143
- sideEffects: true,
144
- use: getVanillaExtractCssLoaders(options, resolvedNextConfig.assetPrefix, hasAppDir)
145
- });
138
+ return (nextConfig = {}) => {
139
+ const {
140
+ unstable_turbopack: turbopackOptions = {},
141
+ ...webpackPluginOptions
142
+ } = pluginOptions;
143
+ const {
144
+ mode: turbopackMode = 'off',
145
+ glob: turbopackGlob = ['**/*.css.{js,cjs,mjs,jsx,ts,tsx}']
146
+ } = turbopackOptions;
147
+ // detect Next version and decide whether to configure turbopack
148
+ const nextVersion = (() => {
149
+ try {
150
+ // resolve from the consumer app's cwd, not this package
151
+ const requireFromCwd = node_module.createRequire(path__namespace.join(process.cwd(), 'package.json'));
152
+ const pkg = requireFromCwd('next/package.json');
153
+ return (pkg === null || pkg === void 0 ? void 0 : pkg.version) ?? null;
154
+ } catch {
155
+ return null;
156
+ }
157
+ })();
158
+ const coerced = nextVersion ? semver__default["default"].coerce(nextVersion) : null;
159
+ const supportsTurbopackRules = !!coerced && semver__default["default"].gte(coerced, '16.0.0');
160
+ const enableTurbopack = turbopackMode === 'on' || turbopackMode === 'auto' && supportsTurbopackRules;
161
+ if (turbopackMode === 'on' && !supportsTurbopackRules) {
162
+ console.warn(`[@vanilla-extract/next-plugin] Turbopack is configured but does not seem supported. Expected Next.js >= 16.0.0, got ${nextVersion}`);
163
+ }
164
+ let turbopack;
165
+ if (enableTurbopack) {
166
+ turbopack = {
167
+ ...(nextConfig.turbopack || {})
168
+ };
169
+ if (turbopackGlob.some(glob => {
170
+ var _turbopack$rules;
171
+ return (_turbopack$rules = turbopack.rules) === null || _turbopack$rules === void 0 ? void 0 : _turbopack$rules[glob];
172
+ })) {
173
+ throw new Error('Vanilla extract could not be applied automatically due to conflicting turbopack rules');
174
+ }
175
+ const vanillaExtractRule = {
176
+ as: '*.js',
177
+ loaders: [{
178
+ loader: require$1.resolve('@vanilla-extract/turbopack-plugin'),
179
+ options: {
180
+ nextEnv: nextConfig.env ?? null,
181
+ outputCss: pluginOptions.outputCss ?? null,
182
+ identifiers: pluginOptions.identifiers ?? null
183
+ }
184
+ }]
185
+ };
186
+ const vanillaExtractCssRule = {
187
+ as: '*.css',
188
+ loaders: [require$1.resolve('@vanilla-extract/turbopack-plugin')]
189
+ };
190
+ turbopack.rules = {
191
+ ...(turbopack.rules || {}),
192
+ ...Object.fromEntries(turbopackGlob.map(glob => [glob, vanillaExtractRule])),
193
+ 'vanilla.virtual.css': vanillaExtractCssRule
194
+ };
195
+ }
196
+ const baseConfig = {
197
+ ...nextConfig,
198
+ webpack(config, options) {
199
+ var _resolvedNextConfig$e;
200
+ const {
201
+ dir,
202
+ dev,
203
+ config: resolvedNextConfig
204
+ } = options;
205
+
206
+ // https://github.com/vercel/next.js/blob/1fb4cad2a8329811b5ccde47217b4a6ae739124e/packages/next/build/index.ts#L336
207
+ // https://github.com/vercel/next.js/blob/1fb4cad2a8329811b5ccde47217b4a6ae739124e/packages/next/build/webpack-config.ts#L626
208
+ // https://github.com/vercel/next.js/pull/43916
209
+ // on Next.js 12, findPagesDirResult is a string. on Next.js 13, findPagesDirResult is an object
210
+ const findPagesDirResult = findPagesDir.findPagesDir(dir, ((_resolvedNextConfig$e = resolvedNextConfig.experimental) === null || _resolvedNextConfig$e === void 0 ? void 0 : _resolvedNextConfig$e.appDir) ?? false);
211
+ // Skip nextConfig check since appDir is stable feature after Next.js 13.4
212
+ const hasAppDir = !!(findPagesDirResult && findPagesDirResult.appDir);
213
+ const outputCss = true;
214
+
215
+ // https://github.com/vercel/next.js/blob/6e5b935fd7a61497f6854a81aec7df3a5dbf61ac/packages/next/src/build/webpack/config/helpers.ts#L12-L21
216
+ const cssRules = config.module.rules.find(rule => Array.isArray(rule.oneOf) && rule.oneOf.some(({
217
+ test
218
+ }) => typeof test === 'object' && typeof test.test === 'function' && test.test('filename.css'))).oneOf;
219
+
220
+ // https://github.com/SukkaW/style9-webpack/blob/f51c46bbcd95ea3b988d3559c3b35cc056874366/src/next-appdir/index.ts#L187-L190
221
+ cssRules.unshift({
222
+ test: /vanilla\.virtual\.css/i,
223
+ sideEffects: true,
224
+ use: getVanillaExtractCssLoaders(options, resolvedNextConfig.assetPrefix, hasAppDir)
225
+ });
146
226
 
147
- // vanilla-extract need to emit the css file on both server and client, both during the
148
- // development and production.
149
- // However, Next.js only add MiniCssExtractPlugin on pages dir + client build + production mode.
150
- //
151
- // To simplify the logic at our side, we will add MiniCssExtractPlugin based on
152
- // the "instanceof" check (We will only add our required MiniCssExtractPlugin if
153
- // Next.js hasn't added it yet).
154
- // This also prevent multiple MiniCssExtractPlugin being added (which will cause
155
- // RealContentHashPlugin to panic)
156
- if (!config.plugins.some(p => p instanceof NextMiniCssExtractPlugin)) {
157
- // HMR reloads the CSS file when the content changes but does not use
158
- // the new file name, which means it can't contain a hash.
159
- const filename = dev ? 'static/css/[name].css' : 'static/css/[contenthash].css';
160
- config.plugins.push(new NextMiniCssExtractPlugin({
161
- filename,
162
- chunkFilename: filename,
163
- // Next.js guarantees that CSS order "doesn't matter", due to imposed
164
- // restrictions:
165
- // 1. Global CSS can only be defined in a single entrypoint (_app)
166
- // 2. CSS Modules generate scoped class names by default and cannot
167
- // include Global CSS (:global() selector).
168
- //
169
- // While not a perfect guarantee (e.g. liberal use of `:global()`
170
- // selector), this assumption is required to code-split CSS.
171
- //
172
- // If this warning were to trigger, it'd be unactionable by the user,
173
- // but likely not valid -- so just disable it.
174
- ignoreOrder: true
227
+ // vanilla-extract need to emit the css file on both server and client, both during the
228
+ // development and production.
229
+ // However, Next.js only add MiniCssExtractPlugin on pages dir + client build + production mode.
230
+ //
231
+ // To simplify the logic at our side, we will add MiniCssExtractPlugin based on
232
+ // the "instanceof" check (We will only add our required MiniCssExtractPlugin if
233
+ // Next.js hasn't added it yet).
234
+ // This also prevent multiple MiniCssExtractPlugin being added (which will cause
235
+ // RealContentHashPlugin to panic)
236
+ if (!config.plugins.some(p => p instanceof NextMiniCssExtractPlugin)) {
237
+ // HMR reloads the CSS file when the content changes but does not use
238
+ // the new file name, which means it can't contain a hash.
239
+ const filename = dev ? 'static/css/[name].css' : 'static/css/[contenthash].css';
240
+ config.plugins.push(new NextMiniCssExtractPlugin({
241
+ filename,
242
+ chunkFilename: filename,
243
+ // Next.js guarantees that CSS order "doesn't matter", due to imposed
244
+ // restrictions:
245
+ // 1. Global CSS can only be defined in a single entrypoint (_app)
246
+ // 2. CSS Modules generate scoped class names by default and cannot
247
+ // include Global CSS (:global() selector).
248
+ //
249
+ // While not a perfect guarantee (e.g. liberal use of `:global()`
250
+ // selector), this assumption is required to code-split CSS.
251
+ //
252
+ // If this warning were to trigger, it'd be unactionable by the user,
253
+ // but likely not valid -- so just disable it.
254
+ ignoreOrder: true
255
+ }));
256
+ }
257
+ config.plugins.push(new next.VanillaExtractPlugin({
258
+ outputCss,
259
+ ...webpackPluginOptions
175
260
  }));
261
+ if (typeof nextConfig.webpack === 'function') {
262
+ return nextConfig.webpack(config, options);
263
+ }
264
+ return config;
176
265
  }
177
- config.plugins.push(new next.VanillaExtractPlugin({
178
- outputCss,
179
- ...pluginOptions
180
- }));
181
- if (typeof nextConfig.webpack === 'function') {
182
- return nextConfig.webpack(config, options);
183
- }
184
- return config;
266
+ };
267
+ if (enableTurbopack && turbopack) {
268
+ return {
269
+ ...baseConfig,
270
+ turbopack
271
+ };
185
272
  }
186
- });
273
+ return baseConfig;
274
+ };
187
275
  };
188
276
 
189
277
  exports.createVanillaExtractPlugin = createVanillaExtractPlugin;
@@ -5,6 +5,8 @@ import { findPagesDir } from 'next/dist/lib/find-pages-dir';
5
5
  import { lazyPostCSS } from 'next/dist/build/webpack/config/blocks/css';
6
6
  import { cssFileResolve } from 'next/dist/build/webpack/config/blocks/css/loaders/file-resolve';
7
7
  import { createRequire } from 'node:module';
8
+ import * as path from 'node:path';
9
+ import semver from 'semver';
8
10
 
9
11
  // @ts-expect-error
10
12
  const require = createRequire(import.meta.url);
@@ -104,77 +106,143 @@ const getVanillaExtractCssLoaders = (options, assetPrefix, hasAppDir) => {
104
106
  return loaders;
105
107
  };
106
108
  const createVanillaExtractPlugin = (pluginOptions = {}) => {
107
- return (nextConfig = {}) => ({
108
- ...nextConfig,
109
- webpack(config, options) {
110
- var _resolvedNextConfig$e;
111
- const {
112
- dir,
113
- dev,
114
- config: resolvedNextConfig
115
- } = options;
109
+ return (nextConfig = {}) => {
110
+ const {
111
+ unstable_turbopack: turbopackOptions = {},
112
+ ...webpackPluginOptions
113
+ } = pluginOptions;
114
+ const {
115
+ mode: turbopackMode = 'off',
116
+ glob: turbopackGlob = ['**/*.css.{js,cjs,mjs,jsx,ts,tsx}']
117
+ } = turbopackOptions;
118
+ // detect Next version and decide whether to configure turbopack
119
+ const nextVersion = (() => {
120
+ try {
121
+ // resolve from the consumer app's cwd, not this package
122
+ const requireFromCwd = createRequire(path.join(process.cwd(), 'package.json'));
123
+ const pkg = requireFromCwd('next/package.json');
124
+ return (pkg === null || pkg === void 0 ? void 0 : pkg.version) ?? null;
125
+ } catch {
126
+ return null;
127
+ }
128
+ })();
129
+ const coerced = nextVersion ? semver.coerce(nextVersion) : null;
130
+ const supportsTurbopackRules = !!coerced && semver.gte(coerced, '16.0.0');
131
+ const enableTurbopack = turbopackMode === 'on' || turbopackMode === 'auto' && supportsTurbopackRules;
132
+ if (turbopackMode === 'on' && !supportsTurbopackRules) {
133
+ console.warn(`[@vanilla-extract/next-plugin] Turbopack is configured but does not seem supported. Expected Next.js >= 16.0.0, got ${nextVersion}`);
134
+ }
135
+ let turbopack;
136
+ if (enableTurbopack) {
137
+ turbopack = {
138
+ ...(nextConfig.turbopack || {})
139
+ };
140
+ if (turbopackGlob.some(glob => {
141
+ var _turbopack$rules;
142
+ return (_turbopack$rules = turbopack.rules) === null || _turbopack$rules === void 0 ? void 0 : _turbopack$rules[glob];
143
+ })) {
144
+ throw new Error('Vanilla extract could not be applied automatically due to conflicting turbopack rules');
145
+ }
146
+ const vanillaExtractRule = {
147
+ as: '*.js',
148
+ loaders: [{
149
+ loader: require.resolve('@vanilla-extract/turbopack-plugin'),
150
+ options: {
151
+ nextEnv: nextConfig.env ?? null,
152
+ outputCss: pluginOptions.outputCss ?? null,
153
+ identifiers: pluginOptions.identifiers ?? null
154
+ }
155
+ }]
156
+ };
157
+ const vanillaExtractCssRule = {
158
+ as: '*.css',
159
+ loaders: [require.resolve('@vanilla-extract/turbopack-plugin')]
160
+ };
161
+ turbopack.rules = {
162
+ ...(turbopack.rules || {}),
163
+ ...Object.fromEntries(turbopackGlob.map(glob => [glob, vanillaExtractRule])),
164
+ 'vanilla.virtual.css': vanillaExtractCssRule
165
+ };
166
+ }
167
+ const baseConfig = {
168
+ ...nextConfig,
169
+ webpack(config, options) {
170
+ var _resolvedNextConfig$e;
171
+ const {
172
+ dir,
173
+ dev,
174
+ config: resolvedNextConfig
175
+ } = options;
116
176
 
117
- // https://github.com/vercel/next.js/blob/1fb4cad2a8329811b5ccde47217b4a6ae739124e/packages/next/build/index.ts#L336
118
- // https://github.com/vercel/next.js/blob/1fb4cad2a8329811b5ccde47217b4a6ae739124e/packages/next/build/webpack-config.ts#L626
119
- // https://github.com/vercel/next.js/pull/43916
120
- // on Next.js 12, findPagesDirResult is a string. on Next.js 13, findPagesDirResult is an object
121
- const findPagesDirResult = findPagesDir(dir, ((_resolvedNextConfig$e = resolvedNextConfig.experimental) === null || _resolvedNextConfig$e === void 0 ? void 0 : _resolvedNextConfig$e.appDir) ?? false);
122
- // Skip nextConfig check since appDir is stable feature after Next.js 13.4
123
- const hasAppDir = !!(findPagesDirResult && findPagesDirResult.appDir);
124
- const outputCss = true;
177
+ // https://github.com/vercel/next.js/blob/1fb4cad2a8329811b5ccde47217b4a6ae739124e/packages/next/build/index.ts#L336
178
+ // https://github.com/vercel/next.js/blob/1fb4cad2a8329811b5ccde47217b4a6ae739124e/packages/next/build/webpack-config.ts#L626
179
+ // https://github.com/vercel/next.js/pull/43916
180
+ // on Next.js 12, findPagesDirResult is a string. on Next.js 13, findPagesDirResult is an object
181
+ const findPagesDirResult = findPagesDir(dir, ((_resolvedNextConfig$e = resolvedNextConfig.experimental) === null || _resolvedNextConfig$e === void 0 ? void 0 : _resolvedNextConfig$e.appDir) ?? false);
182
+ // Skip nextConfig check since appDir is stable feature after Next.js 13.4
183
+ const hasAppDir = !!(findPagesDirResult && findPagesDirResult.appDir);
184
+ const outputCss = true;
125
185
 
126
- // https://github.com/vercel/next.js/blob/6e5b935fd7a61497f6854a81aec7df3a5dbf61ac/packages/next/src/build/webpack/config/helpers.ts#L12-L21
127
- const cssRules = config.module.rules.find(rule => Array.isArray(rule.oneOf) && rule.oneOf.some(({
128
- test
129
- }) => typeof test === 'object' && typeof test.test === 'function' && test.test('filename.css'))).oneOf;
186
+ // https://github.com/vercel/next.js/blob/6e5b935fd7a61497f6854a81aec7df3a5dbf61ac/packages/next/src/build/webpack/config/helpers.ts#L12-L21
187
+ const cssRules = config.module.rules.find(rule => Array.isArray(rule.oneOf) && rule.oneOf.some(({
188
+ test
189
+ }) => typeof test === 'object' && typeof test.test === 'function' && test.test('filename.css'))).oneOf;
130
190
 
131
- // https://github.com/SukkaW/style9-webpack/blob/f51c46bbcd95ea3b988d3559c3b35cc056874366/src/next-appdir/index.ts#L187-L190
132
- cssRules.unshift({
133
- test: /vanilla\.virtual\.css/i,
134
- sideEffects: true,
135
- use: getVanillaExtractCssLoaders(options, resolvedNextConfig.assetPrefix, hasAppDir)
136
- });
191
+ // https://github.com/SukkaW/style9-webpack/blob/f51c46bbcd95ea3b988d3559c3b35cc056874366/src/next-appdir/index.ts#L187-L190
192
+ cssRules.unshift({
193
+ test: /vanilla\.virtual\.css/i,
194
+ sideEffects: true,
195
+ use: getVanillaExtractCssLoaders(options, resolvedNextConfig.assetPrefix, hasAppDir)
196
+ });
137
197
 
138
- // vanilla-extract need to emit the css file on both server and client, both during the
139
- // development and production.
140
- // However, Next.js only add MiniCssExtractPlugin on pages dir + client build + production mode.
141
- //
142
- // To simplify the logic at our side, we will add MiniCssExtractPlugin based on
143
- // the "instanceof" check (We will only add our required MiniCssExtractPlugin if
144
- // Next.js hasn't added it yet).
145
- // This also prevent multiple MiniCssExtractPlugin being added (which will cause
146
- // RealContentHashPlugin to panic)
147
- if (!config.plugins.some(p => p instanceof NextMiniCssExtractPlugin)) {
148
- // HMR reloads the CSS file when the content changes but does not use
149
- // the new file name, which means it can't contain a hash.
150
- const filename = dev ? 'static/css/[name].css' : 'static/css/[contenthash].css';
151
- config.plugins.push(new NextMiniCssExtractPlugin({
152
- filename,
153
- chunkFilename: filename,
154
- // Next.js guarantees that CSS order "doesn't matter", due to imposed
155
- // restrictions:
156
- // 1. Global CSS can only be defined in a single entrypoint (_app)
157
- // 2. CSS Modules generate scoped class names by default and cannot
158
- // include Global CSS (:global() selector).
159
- //
160
- // While not a perfect guarantee (e.g. liberal use of `:global()`
161
- // selector), this assumption is required to code-split CSS.
162
- //
163
- // If this warning were to trigger, it'd be unactionable by the user,
164
- // but likely not valid -- so just disable it.
165
- ignoreOrder: true
198
+ // vanilla-extract need to emit the css file on both server and client, both during the
199
+ // development and production.
200
+ // However, Next.js only add MiniCssExtractPlugin on pages dir + client build + production mode.
201
+ //
202
+ // To simplify the logic at our side, we will add MiniCssExtractPlugin based on
203
+ // the "instanceof" check (We will only add our required MiniCssExtractPlugin if
204
+ // Next.js hasn't added it yet).
205
+ // This also prevent multiple MiniCssExtractPlugin being added (which will cause
206
+ // RealContentHashPlugin to panic)
207
+ if (!config.plugins.some(p => p instanceof NextMiniCssExtractPlugin)) {
208
+ // HMR reloads the CSS file when the content changes but does not use
209
+ // the new file name, which means it can't contain a hash.
210
+ const filename = dev ? 'static/css/[name].css' : 'static/css/[contenthash].css';
211
+ config.plugins.push(new NextMiniCssExtractPlugin({
212
+ filename,
213
+ chunkFilename: filename,
214
+ // Next.js guarantees that CSS order "doesn't matter", due to imposed
215
+ // restrictions:
216
+ // 1. Global CSS can only be defined in a single entrypoint (_app)
217
+ // 2. CSS Modules generate scoped class names by default and cannot
218
+ // include Global CSS (:global() selector).
219
+ //
220
+ // While not a perfect guarantee (e.g. liberal use of `:global()`
221
+ // selector), this assumption is required to code-split CSS.
222
+ //
223
+ // If this warning were to trigger, it'd be unactionable by the user,
224
+ // but likely not valid -- so just disable it.
225
+ ignoreOrder: true
226
+ }));
227
+ }
228
+ config.plugins.push(new VanillaExtractPlugin({
229
+ outputCss,
230
+ ...webpackPluginOptions
166
231
  }));
232
+ if (typeof nextConfig.webpack === 'function') {
233
+ return nextConfig.webpack(config, options);
234
+ }
235
+ return config;
167
236
  }
168
- config.plugins.push(new VanillaExtractPlugin({
169
- outputCss,
170
- ...pluginOptions
171
- }));
172
- if (typeof nextConfig.webpack === 'function') {
173
- return nextConfig.webpack(config, options);
174
- }
175
- return config;
237
+ };
238
+ if (enableTurbopack && turbopack) {
239
+ return {
240
+ ...baseConfig,
241
+ turbopack
242
+ };
176
243
  }
177
- });
244
+ return baseConfig;
245
+ };
178
246
  };
179
247
 
180
248
  export { createVanillaExtractPlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vanilla-extract/next-plugin",
3
- "version": "2.4.17",
3
+ "version": "2.5.0",
4
4
  "description": "Zero-runtime Stylesheets-in-TypeScript",
5
5
  "main": "dist/vanilla-extract-next-plugin.cjs.js",
6
6
  "module": "dist/vanilla-extract-next-plugin.esm.js",
@@ -21,12 +21,15 @@
21
21
  "author": "SEEK",
22
22
  "license": "MIT",
23
23
  "dependencies": {
24
- "@vanilla-extract/webpack-plugin": "^2.3.25"
24
+ "semver": "^7.6.3",
25
+ "@vanilla-extract/turbopack-plugin": "^0.1.0",
26
+ "@vanilla-extract/webpack-plugin": "^2.3.26"
25
27
  },
26
28
  "peerDependencies": {
27
29
  "next": ">=12.1.7"
28
30
  },
29
31
  "devDependencies": {
32
+ "@types/semver": "^7.7.1",
30
33
  "next": "12.3.4",
31
34
  "webpack": "^5.90.0"
32
35
  }