@navita/next-plugin 0.0.0 → 0.0.4
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.md +21 -0
- package/fromServerLoader.d.ts +5 -0
- package/fromServerLoader.js +13 -0
- package/fromServerLoader.mjs +11 -0
- package/index.d.ts +6 -3
- package/index.js +156 -125
- package/index.mjs +157 -126
- package/package.json +14 -4
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Alexander Liljengård
|
|
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.
|
|
@@ -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 {
|
|
1
|
+
import { Options } from '@navita/webpack-plugin';
|
|
2
2
|
import { NextConfig } from 'next';
|
|
3
3
|
|
|
4
|
-
type
|
|
5
|
-
|
|
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
|
|
5
|
-
var
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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 {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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.
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"private": false,
|
|
6
|
+
"sideEffects": false,
|
|
4
7
|
"exports": {
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
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": "*",
|