@navita/next-plugin 0.0.0 → 0.0.2

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.
@@ -0,0 +1,5 @@
1
+ import { LoaderContext } from 'webpack';
2
+
3
+ declare function pitch(this: LoaderContext<unknown>): string;
4
+
5
+ export { pitch };
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ var webpackPlugin = require('@navita/webpack-plugin');
4
+
5
+ function pitch() {
6
+ this._module.loaders = [];
7
+ const dependency = webpackPlugin.getNavitaDependency(this._compiler.webpack);
8
+ const { cssHash , issuerPath } = Object.fromEntries(new URLSearchParams(this.resourceQuery).entries());
9
+ this._module.addDependency(new dependency(issuerPath, cssHash));
10
+ return '';
11
+ }
12
+
13
+ exports.pitch = pitch;
@@ -0,0 +1,11 @@
1
+ import { getNavitaDependency } from '@navita/webpack-plugin';
2
+
3
+ function pitch() {
4
+ this._module.loaders = [];
5
+ const dependency = getNavitaDependency(this._compiler.webpack);
6
+ const { cssHash , issuerPath } = Object.fromEntries(new URLSearchParams(this.resourceQuery).entries());
7
+ this._module.addDependency(new dependency(issuerPath, cssHash));
8
+ return '';
9
+ }
10
+
11
+ export { pitch };
package/index.d.ts CHANGED
@@ -1,7 +1,10 @@
1
- import { NavitaPlugin } from '@navita/webpack-plugin';
1
+ import { Options } from '@navita/webpack-plugin';
2
2
  import { NextConfig } from 'next';
3
3
 
4
- type NavitaConfig = ConstructorParameters<typeof NavitaPlugin>[0];
5
- declare const createNavitaStylePlugin: (navitaConfig?: NavitaConfig) => (nextConfig: NextConfig) => NextConfig;
4
+ type WebpackOptions = Options;
5
+ interface Config extends WebpackOptions {
6
+ singleCssFile?: boolean;
7
+ }
8
+ declare const createNavitaStylePlugin: (navitaConfig?: Config) => (nextConfig: NextConfig) => NextConfig;
6
9
 
7
10
  export { createNavitaStylePlugin };
package/index.js CHANGED
@@ -1,143 +1,174 @@
1
1
  'use strict';
2
2
 
3
3
  var webpackPlugin = require('@navita/webpack-plugin');
4
- var browserslist = require('browserslist');
5
- var css = require('next/dist/build/webpack/config/blocks/css');
6
- var client = require('next/dist/build/webpack/config/blocks/css/loaders/client');
7
- var webpack = require('webpack');
4
+ var NextMiniCssExtractPlugin = require('next/dist/build/webpack/plugins/mini-css-extract-plugin');
5
+ var findPagesDir = require('next/dist/lib/find-pages-dir');
8
6
 
9
- /**
10
- * Next.js adds a cache busting query string to document:
11
- * https://github.com/vercel/next.js/blob/805183e3e93e15db7bc6c66837925431791a2250/packages/next/src/pages/_document.tsx#L481
12
- * mini-css-extract-plugin checks for existing css files with an exact match:
13
- * https://github.com/webpack-contrib/mini-css-extract-plugin/blob/2985918b79cd05cd5390e8b6d70e2009ea531521/src/index.js#L919
14
- *
15
- * This webpack plugins fixes that by adding a data-href attribute to the link tag, since that's also part
16
- * of the comparison that mini-css-extract-plugin does.
17
- */ class FixLinkTagsPlugin {
18
- static pluginName = 'FixLinkTagsPlugin';
19
- constructor(name = 'styles.css'){
20
- this.name = name;
7
+ const merge = (...merge)=>{
8
+ const result = {};
9
+ for (const usedIds of merge){
10
+ for(const key in usedIds){
11
+ result[key] = [
12
+ ...result[key] || [],
13
+ ...usedIds[key] || []
14
+ ];
15
+ }
16
+ }
17
+ for(const key1 in result){
18
+ result[key1] = [
19
+ ...new Set(result[key1])
20
+ ];
21
+ }
22
+ return result;
23
+ };
24
+ const intersect = (...intersect)=>{
25
+ const result = {};
26
+ for (const usedIds of intersect){
27
+ for(const key in usedIds){
28
+ result[key] = result[key] ? result[key].filter((id)=>usedIds[key].includes(id)) : usedIds[key];
29
+ }
21
30
  }
22
- apply(compiler) {
23
- const name = this.name;
24
- class AddDataHrefToLink extends webpack.RuntimeModule {
25
- constructor(){
26
- super(FixLinkTagsPlugin.pluginName, webpack.RuntimeModule.STAGE_NORMAL);
31
+ return result;
32
+ };
33
+ // structuredClone would be better, but since Next.js version 13 is at node 16.14.0,
34
+ // we can't use it.
35
+ const copy = (source)=>JSON.parse(JSON.stringify(source));
36
+ const removeParentFromCurrent = (usedIds, parentUsedIds)=>{
37
+ for(const key in parentUsedIds){
38
+ if (usedIds[key] && parentUsedIds[key]) {
39
+ usedIds[key] = usedIds[key].filter((id)=>!parentUsedIds[key].includes(id));
40
+ }
41
+ }
42
+ };
43
+ function optimizeCSSOutput(output) {
44
+ const nameToChunk = Object.fromEntries(Array.from(output.keys()).filter((x)=>x.name).map((x)=>[
45
+ x.name,
46
+ x
47
+ ]));
48
+ const getAllParentUsedIds = (chunk)=>{
49
+ const { name: route } = chunk;
50
+ if (!route) {
51
+ // If we don't have a name, it's a dynamic chunk.
52
+ const value = output.get(chunk);
53
+ if (value.parents.length === 0) {
54
+ return [];
55
+ }
56
+ return [
57
+ intersect(...value.parents.map((parent)=>merge(...getAllParentUsedIds(parent), output.get(parent).usedIds)))
58
+ ];
59
+ }
60
+ if (route.startsWith('pages/')) {
61
+ const routes = [
62
+ 'pages/_document',
63
+ 'pages/_app',
64
+ route
65
+ ];
66
+ const currentRouteIndex = routes.indexOf(route);
67
+ return routes.filter((_, index)=>currentRouteIndex > index).map((x)=>output.get(nameToChunk[x])).filter(Boolean).map((x)=>copy(x.usedIds));
68
+ }
69
+ const parts = route.split('/');
70
+ const parents = [];
71
+ let currentPart = '';
72
+ for (const part of parts){
73
+ currentPart = [
74
+ currentPart,
75
+ part
76
+ ].filter(Boolean).join('/');
77
+ const possibleParent = `${currentPart}/layout`;
78
+ if (route === possibleParent) {
79
+ continue;
27
80
  }
28
- generate() {
29
- return webpack.Template.asString([
30
- `const styleSheets = document.querySelectorAll('link[rel="stylesheet"][href*="${name}"]');`,
31
- `for (const styleSheet of styleSheets) {`,
32
- webpack.Template.indent(`styleSheet.setAttribute('data-href', (styleSheet.getAttribute('href') || '').replace(/\\?.*$/, ''));`),
33
- `}`
34
- ]);
81
+ const parentChunk = nameToChunk[possibleParent];
82
+ if (output.has(parentChunk)) {
83
+ parents.push(copy(output.get(parentChunk).usedIds));
35
84
  }
36
85
  }
37
- compiler.hooks.thisCompilation.tap(FixLinkTagsPlugin.pluginName, (compilation)=>{
38
- compilation.hooks.runtimeRequirementInTree.for(webpack.RuntimeGlobals.ensureChunkHandlers).tap(FixLinkTagsPlugin.pluginName, (chunk)=>{
39
- compilation.addRuntimeModule(chunk, new AddDataHrefToLink());
40
- });
86
+ return parents;
87
+ };
88
+ const newOutput = new Map();
89
+ for (const chunk of output.keys()){
90
+ const currentUsedIds = copy(output.get(chunk).usedIds);
91
+ for (const parent of getAllParentUsedIds(chunk)){
92
+ removeParentFromCurrent(currentUsedIds, parent);
93
+ }
94
+ newOutput.set(chunk, {
95
+ ...output.get(chunk),
96
+ usedIds: currentUsedIds
41
97
  });
42
98
  }
99
+ return newOutput;
43
100
  }
44
101
 
45
- function getCssLoader() {
46
- try {
47
- // v12+
48
- return require.resolve('next/dist/build/webpack/loaders/css-loader/src');
49
- } catch (_) {
50
- return 'css-loader';
51
- }
52
- }
53
-
54
- function getNextCssRules(config) {
55
- return config.module?.rules?.find((rule)=>typeof rule === "object" && Array.isArray(rule.oneOf) && rule.oneOf.some(({ test })=>test instanceof RegExp && typeof test.test === "function" && test.test("filename.css")))?.oneOf;
56
- }
57
-
58
- const NextMiniCssExtractPlugin = require("next/dist/build/webpack/plugins/mini-css-extract-plugin").default;
59
- const getSupportedBrowsers = (dir, isDevelopment)=>{
60
- try {
61
- return browserslist.loadConfig({
62
- path: dir,
63
- env: isDevelopment ? "development" : "production"
64
- });
65
- } catch {}
66
- return undefined;
67
- };
68
- const navitaStyleConfig = (nextConfig, navitaConfig = {})=>{
69
- return {
70
- webpack (config, options) {
71
- const { dir , dev , isServer } = options;
72
- const cssRules = getNextCssRules(config);
73
- const outputLoaders = [
74
- {
75
- loader: getCssLoader(),
76
- options: {
77
- postcss: ()=>css.lazyPostCSS(dir, getSupportedBrowsers(dir, dev), undefined)
102
+ const MiniCssExtractPlugin = NextMiniCssExtractPlugin['default'];
103
+ const createNavitaStylePlugin = (navitaConfig = {})=>(nextConfig)=>Object.assign({}, nextConfig, {
104
+ webpack (config, options) {
105
+ const { dir , config: resolvedNextConfig , dev } = options;
106
+ config.plugins?.push({
107
+ apply (compiler) {
108
+ // We call the getNavitaModule function here
109
+ // so that NavitaModule is created with what's required for the next.js rsc to client entry promotion:
110
+ webpackPlugin.getNavitaModule(compiler.webpack, ({ cssHash , issuerPath })=>({
111
+ // The resourceResolveData is used by next.js to promote server and ssr entries to client entries:
112
+ // https://github.com/vercel/next.js/blob/f3132354285fb18c290bf9aad7f8dc7e0550105d/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts#L590
113
+ resourceResolveData: {
114
+ path: '',
115
+ query: '?' + new URLSearchParams({
116
+ cssHash,
117
+ issuerPath
118
+ }).toString()
119
+ },
120
+ // We set the resource to ".css"
121
+ // to trick next.js into thinking this is a css module:
122
+ // https://github.com/vercel/next.js/blob/f3132354285fb18c290bf9aad7f8dc7e0550105d/packages/next/src/build/webpack/loaders/utils.ts#L24
123
+ resource: '.css'
124
+ }));
78
125
  }
79
- }
80
- ];
81
- if (!isServer) {
82
- const styleLoader = client.getClientStyleLoader({
83
- // False to force the use of MiniCssExtractPlugin
84
- isDevelopment: false,
85
- assetPrefix: options.config.assetPrefix,
86
- hasAppDir: false,
87
- isAppDir: false
88
126
  });
89
- outputLoaders.unshift(styleLoader);
90
- }
91
- cssRules?.unshift({
92
- test: webpackPlugin.getEmptyCssFilePath(),
93
- sideEffects: true,
94
- use: outputLoaders
95
- });
96
- // Add next's MiniCssExtractPlugin if it's not already added
97
- // todo: ^- only on development?
98
- if (!config.plugins?.some((plugin)=>plugin instanceof NextMiniCssExtractPlugin)) {
99
- // HMR reloads the CSS file when the content changes but does not use
100
- // the new file name, which means it can't contain a hash.
101
- // Logic adopted from https://git.io/JtdBy
102
- config.plugins?.push(new NextMiniCssExtractPlugin({
103
- filename: "static/css/[name].css"
104
- }));
105
- }
106
- config.plugins?.push(new webpackPlugin.NavitaPlugin({
107
- ...navitaConfig,
108
- outputCss: !isServer,
109
- isServer
110
- }));
111
- if (!isServer && dev) {
112
- config.plugins?.push(new FixLinkTagsPlugin());
113
- }
114
- if (typeof nextConfig.webpack === "function") {
115
- return nextConfig.webpack(config, options);
116
- }
117
- config.optimization = {
118
- ...config.optimization,
119
- splitChunks: {
120
- ...config.optimization?.splitChunks,
121
- cacheGroups: {
122
- ...config.optimization?.splitChunks ? config.optimization.splitChunks.cacheGroups : {},
123
- styles: {
124
- name: 'styles',
125
- type: 'css/mini-extract',
126
- test: webpackPlugin.getEmptyCssFilePath(),
127
- chunks: 'all',
128
- enforce: true
127
+ // This loader promotes the server and ssr entries to client entries:
128
+ config.module?.rules.unshift({
129
+ resourceQuery: [
130
+ /cssHash/,
131
+ /issuerPath/
132
+ ],
133
+ loader: require.resolve("@navita/next-plugin/fromServerLoader")
134
+ });
135
+ const findPagesDirResult = findPagesDir.findPagesDir(dir, !!resolvedNextConfig.experimental.appDir);
136
+ const hasAppDir = !!(findPagesDirResult && findPagesDirResult.appDir);
137
+ const isServer = options.isServer && !(options.nextRuntime === 'edge');
138
+ const outputCss = !isServer || hasAppDir;
139
+ if (!hasAppDir && !isServer) {
140
+ const filename = dev ? 'static/css/[name].css' : 'static/css/[contenthash].css';
141
+ // https://github.com/vercel/next.js/blob/930db5c1afbe541a0b2357c26123c2b365b56624/packages/next/src/build/webpack/config/blocks/css/index.ts#L595
142
+ config.plugins.push(new MiniCssExtractPlugin({
143
+ filename,
144
+ chunkFilename: filename,
145
+ ignoreOrder: true
146
+ }));
147
+ }
148
+ if (navitaConfig?.singleCssFile) {
149
+ config.optimization.splitChunks = {
150
+ ...config.optimization.splitChunks || {},
151
+ cacheGroups: {
152
+ ...config.optimization.splitChunks['cacheGroups'] || {},
153
+ navita: {
154
+ chunks: 'all',
155
+ enforce: true,
156
+ name: 'navita',
157
+ type: webpackPlugin.NAVITA_MODULE_TYPE
158
+ }
129
159
  }
130
- }
160
+ };
131
161
  }
132
- };
133
- return config;
134
- }
135
- };
136
- };
137
- const createNavitaStylePlugin = (navitaConfig = {})=>{
138
- return (nextConfig)=>{
139
- return Object.assign({}, nextConfig, navitaStyleConfig(nextConfig, navitaConfig));
140
- };
141
- };
162
+ config.plugins?.push(new webpackPlugin.NavitaPlugin({
163
+ outputCss,
164
+ ...navitaConfig,
165
+ optimizeCSSOutput
166
+ }));
167
+ if (typeof nextConfig.webpack === "function") {
168
+ return nextConfig.webpack(config, options);
169
+ }
170
+ return config;
171
+ }
172
+ });
142
173
 
143
174
  exports.createNavitaStylePlugin = createNavitaStylePlugin;
package/index.mjs CHANGED
@@ -1,143 +1,174 @@
1
1
  import { createRequire as createRequire$1 } from 'module';
2
2
  const require = createRequire$1(import.meta.url);
3
- import { getEmptyCssFilePath, NavitaPlugin } from '@navita/webpack-plugin';
4
- import { loadConfig } from 'browserslist';
5
- import { lazyPostCSS } from 'next/dist/build/webpack/config/blocks/css';
6
- import { getClientStyleLoader } from 'next/dist/build/webpack/config/blocks/css/loaders/client';
7
- import { RuntimeGlobals, RuntimeModule, Template } from 'webpack';
3
+ import { getNavitaModule, NAVITA_MODULE_TYPE, NavitaPlugin } from '@navita/webpack-plugin';
4
+ import NextMiniCssExtractPlugin from 'next/dist/build/webpack/plugins/mini-css-extract-plugin';
5
+ import { findPagesDir } from 'next/dist/lib/find-pages-dir';
8
6
 
9
- /**
10
- * Next.js adds a cache busting query string to document:
11
- * https://github.com/vercel/next.js/blob/805183e3e93e15db7bc6c66837925431791a2250/packages/next/src/pages/_document.tsx#L481
12
- * mini-css-extract-plugin checks for existing css files with an exact match:
13
- * https://github.com/webpack-contrib/mini-css-extract-plugin/blob/2985918b79cd05cd5390e8b6d70e2009ea531521/src/index.js#L919
14
- *
15
- * This webpack plugins fixes that by adding a data-href attribute to the link tag, since that's also part
16
- * of the comparison that mini-css-extract-plugin does.
17
- */ class FixLinkTagsPlugin {
18
- static pluginName = 'FixLinkTagsPlugin';
19
- constructor(name = 'styles.css'){
20
- this.name = name;
7
+ const merge = (...merge)=>{
8
+ const result = {};
9
+ for (const usedIds of merge){
10
+ for(const key in usedIds){
11
+ result[key] = [
12
+ ...result[key] || [],
13
+ ...usedIds[key] || []
14
+ ];
15
+ }
16
+ }
17
+ for(const key1 in result){
18
+ result[key1] = [
19
+ ...new Set(result[key1])
20
+ ];
21
+ }
22
+ return result;
23
+ };
24
+ const intersect = (...intersect)=>{
25
+ const result = {};
26
+ for (const usedIds of intersect){
27
+ for(const key in usedIds){
28
+ result[key] = result[key] ? result[key].filter((id)=>usedIds[key].includes(id)) : usedIds[key];
29
+ }
21
30
  }
22
- apply(compiler) {
23
- const name = this.name;
24
- class AddDataHrefToLink extends RuntimeModule {
25
- constructor(){
26
- super(FixLinkTagsPlugin.pluginName, RuntimeModule.STAGE_NORMAL);
31
+ return result;
32
+ };
33
+ // structuredClone would be better, but since Next.js version 13 is at node 16.14.0,
34
+ // we can't use it.
35
+ const copy = (source)=>JSON.parse(JSON.stringify(source));
36
+ const removeParentFromCurrent = (usedIds, parentUsedIds)=>{
37
+ for(const key in parentUsedIds){
38
+ if (usedIds[key] && parentUsedIds[key]) {
39
+ usedIds[key] = usedIds[key].filter((id)=>!parentUsedIds[key].includes(id));
40
+ }
41
+ }
42
+ };
43
+ function optimizeCSSOutput(output) {
44
+ const nameToChunk = Object.fromEntries(Array.from(output.keys()).filter((x)=>x.name).map((x)=>[
45
+ x.name,
46
+ x
47
+ ]));
48
+ const getAllParentUsedIds = (chunk)=>{
49
+ const { name: route } = chunk;
50
+ if (!route) {
51
+ // If we don't have a name, it's a dynamic chunk.
52
+ const value = output.get(chunk);
53
+ if (value.parents.length === 0) {
54
+ return [];
55
+ }
56
+ return [
57
+ intersect(...value.parents.map((parent)=>merge(...getAllParentUsedIds(parent), output.get(parent).usedIds)))
58
+ ];
59
+ }
60
+ if (route.startsWith('pages/')) {
61
+ const routes = [
62
+ 'pages/_document',
63
+ 'pages/_app',
64
+ route
65
+ ];
66
+ const currentRouteIndex = routes.indexOf(route);
67
+ return routes.filter((_, index)=>currentRouteIndex > index).map((x)=>output.get(nameToChunk[x])).filter(Boolean).map((x)=>copy(x.usedIds));
68
+ }
69
+ const parts = route.split('/');
70
+ const parents = [];
71
+ let currentPart = '';
72
+ for (const part of parts){
73
+ currentPart = [
74
+ currentPart,
75
+ part
76
+ ].filter(Boolean).join('/');
77
+ const possibleParent = `${currentPart}/layout`;
78
+ if (route === possibleParent) {
79
+ continue;
27
80
  }
28
- generate() {
29
- return Template.asString([
30
- `const styleSheets = document.querySelectorAll('link[rel="stylesheet"][href*="${name}"]');`,
31
- `for (const styleSheet of styleSheets) {`,
32
- Template.indent(`styleSheet.setAttribute('data-href', (styleSheet.getAttribute('href') || '').replace(/\\?.*$/, ''));`),
33
- `}`
34
- ]);
81
+ const parentChunk = nameToChunk[possibleParent];
82
+ if (output.has(parentChunk)) {
83
+ parents.push(copy(output.get(parentChunk).usedIds));
35
84
  }
36
85
  }
37
- compiler.hooks.thisCompilation.tap(FixLinkTagsPlugin.pluginName, (compilation)=>{
38
- compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.ensureChunkHandlers).tap(FixLinkTagsPlugin.pluginName, (chunk)=>{
39
- compilation.addRuntimeModule(chunk, new AddDataHrefToLink());
40
- });
86
+ return parents;
87
+ };
88
+ const newOutput = new Map();
89
+ for (const chunk of output.keys()){
90
+ const currentUsedIds = copy(output.get(chunk).usedIds);
91
+ for (const parent of getAllParentUsedIds(chunk)){
92
+ removeParentFromCurrent(currentUsedIds, parent);
93
+ }
94
+ newOutput.set(chunk, {
95
+ ...output.get(chunk),
96
+ usedIds: currentUsedIds
41
97
  });
42
98
  }
99
+ return newOutput;
43
100
  }
44
101
 
45
- function getCssLoader() {
46
- try {
47
- // v12+
48
- return require.resolve('next/dist/build/webpack/loaders/css-loader/src');
49
- } catch (_) {
50
- return 'css-loader';
51
- }
52
- }
53
-
54
- function getNextCssRules(config) {
55
- return config.module?.rules?.find((rule)=>typeof rule === "object" && Array.isArray(rule.oneOf) && rule.oneOf.some(({ test })=>test instanceof RegExp && typeof test.test === "function" && test.test("filename.css")))?.oneOf;
56
- }
57
-
58
- const NextMiniCssExtractPlugin = require("next/dist/build/webpack/plugins/mini-css-extract-plugin").default;
59
- const getSupportedBrowsers = (dir, isDevelopment)=>{
60
- try {
61
- return loadConfig({
62
- path: dir,
63
- env: isDevelopment ? "development" : "production"
64
- });
65
- } catch {}
66
- return undefined;
67
- };
68
- const navitaStyleConfig = (nextConfig, navitaConfig = {})=>{
69
- return {
70
- webpack (config, options) {
71
- const { dir , dev , isServer } = options;
72
- const cssRules = getNextCssRules(config);
73
- const outputLoaders = [
74
- {
75
- loader: getCssLoader(),
76
- options: {
77
- postcss: ()=>lazyPostCSS(dir, getSupportedBrowsers(dir, dev), undefined)
102
+ const MiniCssExtractPlugin = NextMiniCssExtractPlugin['default'];
103
+ const createNavitaStylePlugin = (navitaConfig = {})=>(nextConfig)=>Object.assign({}, nextConfig, {
104
+ webpack (config, options) {
105
+ const { dir , config: resolvedNextConfig , dev } = options;
106
+ config.plugins?.push({
107
+ apply (compiler) {
108
+ // We call the getNavitaModule function here
109
+ // so that NavitaModule is created with what's required for the next.js rsc to client entry promotion:
110
+ getNavitaModule(compiler.webpack, ({ cssHash , issuerPath })=>({
111
+ // The resourceResolveData is used by next.js to promote server and ssr entries to client entries:
112
+ // https://github.com/vercel/next.js/blob/f3132354285fb18c290bf9aad7f8dc7e0550105d/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts#L590
113
+ resourceResolveData: {
114
+ path: '',
115
+ query: '?' + new URLSearchParams({
116
+ cssHash,
117
+ issuerPath
118
+ }).toString()
119
+ },
120
+ // We set the resource to ".css"
121
+ // to trick next.js into thinking this is a css module:
122
+ // https://github.com/vercel/next.js/blob/f3132354285fb18c290bf9aad7f8dc7e0550105d/packages/next/src/build/webpack/loaders/utils.ts#L24
123
+ resource: '.css'
124
+ }));
78
125
  }
79
- }
80
- ];
81
- if (!isServer) {
82
- const styleLoader = getClientStyleLoader({
83
- // False to force the use of MiniCssExtractPlugin
84
- isDevelopment: false,
85
- assetPrefix: options.config.assetPrefix,
86
- hasAppDir: false,
87
- isAppDir: false
88
126
  });
89
- outputLoaders.unshift(styleLoader);
90
- }
91
- cssRules?.unshift({
92
- test: getEmptyCssFilePath(),
93
- sideEffects: true,
94
- use: outputLoaders
95
- });
96
- // Add next's MiniCssExtractPlugin if it's not already added
97
- // todo: ^- only on development?
98
- if (!config.plugins?.some((plugin)=>plugin instanceof NextMiniCssExtractPlugin)) {
99
- // HMR reloads the CSS file when the content changes but does not use
100
- // the new file name, which means it can't contain a hash.
101
- // Logic adopted from https://git.io/JtdBy
102
- config.plugins?.push(new NextMiniCssExtractPlugin({
103
- filename: "static/css/[name].css"
104
- }));
105
- }
106
- config.plugins?.push(new NavitaPlugin({
107
- ...navitaConfig,
108
- outputCss: !isServer,
109
- isServer
110
- }));
111
- if (!isServer && dev) {
112
- config.plugins?.push(new FixLinkTagsPlugin());
113
- }
114
- if (typeof nextConfig.webpack === "function") {
115
- return nextConfig.webpack(config, options);
116
- }
117
- config.optimization = {
118
- ...config.optimization,
119
- splitChunks: {
120
- ...config.optimization?.splitChunks,
121
- cacheGroups: {
122
- ...config.optimization?.splitChunks ? config.optimization.splitChunks.cacheGroups : {},
123
- styles: {
124
- name: 'styles',
125
- type: 'css/mini-extract',
126
- test: getEmptyCssFilePath(),
127
- chunks: 'all',
128
- enforce: true
127
+ // This loader promotes the server and ssr entries to client entries:
128
+ config.module?.rules.unshift({
129
+ resourceQuery: [
130
+ /cssHash/,
131
+ /issuerPath/
132
+ ],
133
+ loader: require.resolve("@navita/next-plugin/fromServerLoader")
134
+ });
135
+ const findPagesDirResult = findPagesDir(dir, !!resolvedNextConfig.experimental.appDir);
136
+ const hasAppDir = !!(findPagesDirResult && findPagesDirResult.appDir);
137
+ const isServer = options.isServer && !(options.nextRuntime === 'edge');
138
+ const outputCss = !isServer || hasAppDir;
139
+ if (!hasAppDir && !isServer) {
140
+ const filename = dev ? 'static/css/[name].css' : 'static/css/[contenthash].css';
141
+ // https://github.com/vercel/next.js/blob/930db5c1afbe541a0b2357c26123c2b365b56624/packages/next/src/build/webpack/config/blocks/css/index.ts#L595
142
+ config.plugins.push(new MiniCssExtractPlugin({
143
+ filename,
144
+ chunkFilename: filename,
145
+ ignoreOrder: true
146
+ }));
147
+ }
148
+ if (navitaConfig?.singleCssFile) {
149
+ config.optimization.splitChunks = {
150
+ ...config.optimization.splitChunks || {},
151
+ cacheGroups: {
152
+ ...config.optimization.splitChunks['cacheGroups'] || {},
153
+ navita: {
154
+ chunks: 'all',
155
+ enforce: true,
156
+ name: 'navita',
157
+ type: NAVITA_MODULE_TYPE
158
+ }
129
159
  }
130
- }
160
+ };
131
161
  }
132
- };
133
- return config;
134
- }
135
- };
136
- };
137
- const createNavitaStylePlugin = (navitaConfig = {})=>{
138
- return (nextConfig)=>{
139
- return Object.assign({}, nextConfig, navitaStyleConfig(nextConfig, navitaConfig));
140
- };
141
- };
162
+ config.plugins?.push(new NavitaPlugin({
163
+ outputCss,
164
+ ...navitaConfig,
165
+ optimizeCSSOutput
166
+ }));
167
+ if (typeof nextConfig.webpack === "function") {
168
+ return nextConfig.webpack(config, options);
169
+ }
170
+ return config;
171
+ }
172
+ });
142
173
 
143
174
  export { createNavitaStylePlugin };
package/package.json CHANGED
@@ -1,10 +1,20 @@
1
1
  {
2
2
  "name": "@navita/next-plugin",
3
- "version": "0.0.0",
3
+ "version": "0.0.2",
4
+ "license": "MIT",
5
+ "private": false,
6
+ "sideEffects": false,
4
7
  "exports": {
5
- "import": "./index.mjs",
6
- "require": "./index.js",
7
- "types": "./index.d.ts"
8
+ ".": {
9
+ "import": "./index.mjs",
10
+ "require": "./index.js",
11
+ "types": "./index.d.ts"
12
+ },
13
+ "./fromServerLoader": {
14
+ "import": "./fromServerLoader.mjs",
15
+ "require": "./fromServerLoader.js",
16
+ "types": "./fromServerLoader.d.ts"
17
+ }
8
18
  },
9
19
  "dependencies": {
10
20
  "@navita/webpack-plugin": "*",