@navita/next-plugin 0.1.3 → 0.3.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/fromServerLoader.cjs +7 -0
- package/index.cjs +63 -4
- package/index.d.ts +1 -2
- package/package.json +4 -4
- package/fromServerLoader.mjs +0 -11
- package/index.mjs +0 -80
- package/optimizeCSSOutput.mjs +0 -96
package/fromServerLoader.cjs
CHANGED
|
@@ -7,6 +7,13 @@ function pitch() {
|
|
|
7
7
|
const dependency = webpackPlugin.getNavitaDependency(this._compiler.webpack);
|
|
8
8
|
const { cssHash , issuerPath } = Object.fromEntries(new URLSearchParams(this.resourceQuery).entries());
|
|
9
9
|
this._module.addDependency(new dependency(issuerPath, cssHash));
|
|
10
|
+
// We set the layer to something other than WEBPACK_LAYERS.appPagesBrowser to
|
|
11
|
+
// not have the modules included in the next pageManifest.
|
|
12
|
+
// Our modules are empty and aren't used for anything other than for collecting information.
|
|
13
|
+
// And are not even included in the final bundle.
|
|
14
|
+
// https://github.com/vercel/next.js/blob/8c6532fa7045879feb13bb21c530bb1517378e29/packages/next/src/build/webpack/plugins/flight-manifest-plugin.ts#L404
|
|
15
|
+
// https://github.com/vercel/next.js/blob/8c6532fa7045879feb13bb21c530bb1517378e29/packages/next/src/lib/constants.ts#L146
|
|
16
|
+
this._module.layer = 'not-app-pages-browser';
|
|
10
17
|
return '';
|
|
11
18
|
}
|
|
12
19
|
|
package/index.cjs
CHANGED
|
@@ -1,14 +1,37 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var fs = require('node:fs');
|
|
4
|
+
var path = require('node:path');
|
|
3
5
|
var webpackPlugin = require('@navita/webpack-plugin');
|
|
4
|
-
var
|
|
6
|
+
var NextMiniCssExtractPluginDefault = require('next/dist/build/webpack/plugins/mini-css-extract-plugin');
|
|
5
7
|
var findPagesDir = require('next/dist/lib/find-pages-dir');
|
|
6
8
|
var optimizeCSSOutput = require('./optimizeCSSOutput.cjs');
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
function _interopNamespaceDefault(e) {
|
|
11
|
+
var n = Object.create(null);
|
|
12
|
+
if (e) {
|
|
13
|
+
Object.keys(e).forEach(function (k) {
|
|
14
|
+
if (k !== 'default') {
|
|
15
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
16
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return e[k]; }
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
n.default = e;
|
|
24
|
+
return Object.freeze(n);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
|
|
28
|
+
|
|
29
|
+
let renderer;
|
|
30
|
+
let lastCache;
|
|
31
|
+
const MiniCssExtractPlugin = NextMiniCssExtractPluginDefault['default'];
|
|
9
32
|
const createNavitaStylePlugin = (navitaConfig = {})=>(nextConfig)=>Object.assign({}, nextConfig, {
|
|
10
33
|
webpack (config, options) {
|
|
11
|
-
const { dir ,
|
|
34
|
+
const { dir , dev } = options;
|
|
12
35
|
config.plugins?.push({
|
|
13
36
|
apply (compiler) {
|
|
14
37
|
// We call the getNavitaModule function here
|
|
@@ -38,7 +61,7 @@ const createNavitaStylePlugin = (navitaConfig = {})=>(nextConfig)=>Object.assign
|
|
|
38
61
|
],
|
|
39
62
|
loader: require.resolve("@navita/next-plugin/fromServerLoader")
|
|
40
63
|
});
|
|
41
|
-
const findPagesDirResult = findPagesDir.findPagesDir(dir
|
|
64
|
+
const findPagesDirResult = findPagesDir.findPagesDir(dir);
|
|
42
65
|
const hasAppDir = !!(findPagesDirResult && findPagesDirResult.appDir);
|
|
43
66
|
const isServer = options.isServer && !(options.nextRuntime === 'edge');
|
|
44
67
|
const outputCss = !isServer || hasAppDir;
|
|
@@ -65,7 +88,43 @@ const createNavitaStylePlugin = (navitaConfig = {})=>(nextConfig)=>Object.assign
|
|
|
65
88
|
}
|
|
66
89
|
};
|
|
67
90
|
}
|
|
91
|
+
// Next.js creates at least three webpack instances. We can't rely on the webpack cache.
|
|
92
|
+
const { cache , mode } = config;
|
|
93
|
+
const cacheDirectory = typeof cache !== "boolean" && cache.type === "filesystem" ? path.resolve(cache.cacheDirectory, `navita-${mode}`) : undefined;
|
|
94
|
+
const cacheDestination = path.resolve(cacheDirectory, 'data.txt');
|
|
95
|
+
const onRenderInitialized = async (createdRenderer)=>{
|
|
96
|
+
renderer = createdRenderer;
|
|
97
|
+
try {
|
|
98
|
+
// Ensure the cache directory exists:
|
|
99
|
+
await fs__namespace.promises.mkdir(cacheDirectory, {
|
|
100
|
+
recursive: true
|
|
101
|
+
});
|
|
102
|
+
const content = await fs__namespace.promises.readFile(cacheDestination, 'utf-8');
|
|
103
|
+
await renderer.engine.deserialize(content);
|
|
104
|
+
lastCache = renderer.engine.serialize();
|
|
105
|
+
} catch {
|
|
106
|
+
// This will happen if the user doesn't have write access to the cache directory.
|
|
107
|
+
// But the same should happen with the webpack cache.
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
config.plugins?.push({
|
|
111
|
+
apply (compiler) {
|
|
112
|
+
compiler.hooks.afterEmit.tapPromise(`${webpackPlugin.NavitaPlugin.pluginName}-nextjs-custom-cache`, async ()=>{
|
|
113
|
+
if (!renderer) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const newCache = renderer.engine.serialize();
|
|
117
|
+
if (newCache === lastCache) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
lastCache = newCache;
|
|
121
|
+
await fs__namespace.promises.writeFile(cacheDestination, newCache);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
68
125
|
config.plugins?.push(new webpackPlugin.NavitaPlugin({
|
|
126
|
+
useWebpackCache: false,
|
|
127
|
+
onRenderInitialized,
|
|
69
128
|
outputCss,
|
|
70
129
|
...navitaConfig,
|
|
71
130
|
optimizeCSSOutput: optimizeCSSOutput.optimizeCSSOutput
|
package/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Options } from '@navita/webpack-plugin';
|
|
2
2
|
import { NextConfig } from 'next';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
interface Config extends WebpackOptions {
|
|
4
|
+
interface Config extends Omit<Options, 'useWebpackCache' | 'onRenderInitialized'> {
|
|
6
5
|
singleCssFile?: boolean;
|
|
7
6
|
}
|
|
8
7
|
declare const createNavitaStylePlugin: (navitaConfig?: Config) => (nextConfig: NextConfig) => NextConfig;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@navita/next-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Next.js integration for Navita",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"next",
|
|
@@ -13,19 +13,19 @@
|
|
|
13
13
|
"sideEffects": false,
|
|
14
14
|
"exports": {
|
|
15
15
|
".": {
|
|
16
|
-
"import": "./index.
|
|
16
|
+
"import": "./index.cjs",
|
|
17
17
|
"require": "./index.cjs",
|
|
18
18
|
"types": "./index.d.ts"
|
|
19
19
|
},
|
|
20
20
|
"./fromServerLoader": {
|
|
21
|
-
"import": "./fromServerLoader.
|
|
21
|
+
"import": "./fromServerLoader.cjs",
|
|
22
22
|
"require": "./fromServerLoader.cjs",
|
|
23
23
|
"types": "./fromServerLoader.d.ts"
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"browserslist": "^4.21.5",
|
|
28
|
-
"@navita/webpack-plugin": "0.
|
|
28
|
+
"@navita/webpack-plugin": "0.3.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"next": ">=12 || >=13",
|
package/fromServerLoader.mjs
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
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.mjs
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { createRequire as createRequire$1 } from 'module';
|
|
2
|
-
const require = createRequire$1(import.meta.url);
|
|
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';
|
|
6
|
-
import { optimizeCSSOutput } from './optimizeCSSOutput.mjs';
|
|
7
|
-
|
|
8
|
-
const MiniCssExtractPlugin = NextMiniCssExtractPlugin['default'];
|
|
9
|
-
const createNavitaStylePlugin = (navitaConfig = {})=>(nextConfig)=>Object.assign({}, nextConfig, {
|
|
10
|
-
webpack (config, options) {
|
|
11
|
-
const { dir , config: resolvedNextConfig , dev } = options;
|
|
12
|
-
config.plugins?.push({
|
|
13
|
-
apply (compiler) {
|
|
14
|
-
// We call the getNavitaModule function here
|
|
15
|
-
// so that NavitaModule is created with what's required for the next.js rsc to client entry promotion:
|
|
16
|
-
getNavitaModule(compiler.webpack, ({ cssHash , issuerPath })=>({
|
|
17
|
-
// The resourceResolveData is used by next.js to promote server and ssr entries to client entries:
|
|
18
|
-
// https://github.com/vercel/next.js/blob/f3132354285fb18c290bf9aad7f8dc7e0550105d/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts#L590
|
|
19
|
-
resourceResolveData: {
|
|
20
|
-
path: '',
|
|
21
|
-
query: '?' + new URLSearchParams({
|
|
22
|
-
cssHash,
|
|
23
|
-
issuerPath
|
|
24
|
-
}).toString()
|
|
25
|
-
},
|
|
26
|
-
// We set the resource to ".css"
|
|
27
|
-
// to trick next.js into thinking this is a css module:
|
|
28
|
-
// https://github.com/vercel/next.js/blob/f3132354285fb18c290bf9aad7f8dc7e0550105d/packages/next/src/build/webpack/loaders/utils.ts#L24
|
|
29
|
-
resource: '.css'
|
|
30
|
-
}));
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
// This loader promotes the server and ssr entries to client entries:
|
|
34
|
-
config.module?.rules.unshift({
|
|
35
|
-
resourceQuery: [
|
|
36
|
-
/cssHash/,
|
|
37
|
-
/issuerPath/
|
|
38
|
-
],
|
|
39
|
-
loader: require.resolve("@navita/next-plugin/fromServerLoader")
|
|
40
|
-
});
|
|
41
|
-
const findPagesDirResult = findPagesDir(dir, !!resolvedNextConfig.experimental.appDir);
|
|
42
|
-
const hasAppDir = !!(findPagesDirResult && findPagesDirResult.appDir);
|
|
43
|
-
const isServer = options.isServer && !(options.nextRuntime === 'edge');
|
|
44
|
-
const outputCss = !isServer || hasAppDir;
|
|
45
|
-
if (!hasAppDir && !isServer) {
|
|
46
|
-
const filename = dev ? 'static/css/[name].css' : 'static/css/[contenthash].css';
|
|
47
|
-
// https://github.com/vercel/next.js/blob/930db5c1afbe541a0b2357c26123c2b365b56624/packages/next/src/build/webpack/config/blocks/css/index.ts#L595
|
|
48
|
-
config.plugins.push(new MiniCssExtractPlugin({
|
|
49
|
-
filename,
|
|
50
|
-
chunkFilename: filename,
|
|
51
|
-
ignoreOrder: true
|
|
52
|
-
}));
|
|
53
|
-
}
|
|
54
|
-
if (navitaConfig?.singleCssFile) {
|
|
55
|
-
config.optimization.splitChunks = {
|
|
56
|
-
...config.optimization.splitChunks || {},
|
|
57
|
-
cacheGroups: {
|
|
58
|
-
...config.optimization.splitChunks['cacheGroups'] || {},
|
|
59
|
-
navita: {
|
|
60
|
-
chunks: 'all',
|
|
61
|
-
enforce: true,
|
|
62
|
-
name: 'navita',
|
|
63
|
-
type: NAVITA_MODULE_TYPE
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
config.plugins?.push(new NavitaPlugin({
|
|
69
|
-
outputCss,
|
|
70
|
-
...navitaConfig,
|
|
71
|
-
optimizeCSSOutput
|
|
72
|
-
}));
|
|
73
|
-
if (typeof nextConfig.webpack === "function") {
|
|
74
|
-
return nextConfig.webpack(config, options);
|
|
75
|
-
}
|
|
76
|
-
return config;
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
export { createNavitaStylePlugin };
|
package/optimizeCSSOutput.mjs
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
const merge = (...merge)=>{
|
|
2
|
-
const result = {};
|
|
3
|
-
for (const usedIds of merge){
|
|
4
|
-
for(const key in usedIds){
|
|
5
|
-
result[key] = [
|
|
6
|
-
...result[key] || [],
|
|
7
|
-
...usedIds[key] || []
|
|
8
|
-
];
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
for(const key1 in result){
|
|
12
|
-
result[key1] = [
|
|
13
|
-
...new Set(result[key1])
|
|
14
|
-
];
|
|
15
|
-
}
|
|
16
|
-
return result;
|
|
17
|
-
};
|
|
18
|
-
const intersect = (...intersect)=>{
|
|
19
|
-
const result = {};
|
|
20
|
-
for (const usedIds of intersect){
|
|
21
|
-
for(const key in usedIds){
|
|
22
|
-
result[key] = result[key] ? result[key].filter((id)=>usedIds[key].includes(id)) : usedIds[key];
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return result;
|
|
26
|
-
};
|
|
27
|
-
// structuredClone would be better, but since Next.js version 13 is at node 16.14.0,
|
|
28
|
-
// we can't use it.
|
|
29
|
-
const copy = (source)=>JSON.parse(JSON.stringify(source));
|
|
30
|
-
const removeParentFromCurrent = (usedIds, parentUsedIds)=>{
|
|
31
|
-
for(const key in parentUsedIds){
|
|
32
|
-
if (usedIds[key] && parentUsedIds[key]) {
|
|
33
|
-
usedIds[key] = usedIds[key].filter((id)=>!parentUsedIds[key].includes(id));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
function optimizeCSSOutput(output) {
|
|
38
|
-
const nameToChunk = Object.fromEntries(Array.from(output.keys()).filter((x)=>x.name).map((x)=>[
|
|
39
|
-
x.name,
|
|
40
|
-
x
|
|
41
|
-
]));
|
|
42
|
-
const getAllParentUsedIds = (chunk)=>{
|
|
43
|
-
const { name: route } = chunk;
|
|
44
|
-
if (!route) {
|
|
45
|
-
// If we don't have a name, it's a dynamic chunk.
|
|
46
|
-
const value = output.get(chunk);
|
|
47
|
-
if (value.parents.length === 0) {
|
|
48
|
-
return [];
|
|
49
|
-
}
|
|
50
|
-
return [
|
|
51
|
-
intersect(...value.parents.map((parent)=>merge(...getAllParentUsedIds(parent), output.get(parent).usedIds)))
|
|
52
|
-
];
|
|
53
|
-
}
|
|
54
|
-
if (route.startsWith('pages/')) {
|
|
55
|
-
const routes = [
|
|
56
|
-
'pages/_document',
|
|
57
|
-
'pages/_app',
|
|
58
|
-
route
|
|
59
|
-
];
|
|
60
|
-
const currentRouteIndex = routes.indexOf(route);
|
|
61
|
-
return routes.filter((_, index)=>currentRouteIndex > index).map((x)=>output.get(nameToChunk[x])).filter(Boolean).map((x)=>copy(x.usedIds));
|
|
62
|
-
}
|
|
63
|
-
const parts = route.split('/');
|
|
64
|
-
const parents = [];
|
|
65
|
-
let currentPart = '';
|
|
66
|
-
for (const part of parts){
|
|
67
|
-
currentPart = [
|
|
68
|
-
currentPart,
|
|
69
|
-
part
|
|
70
|
-
].filter(Boolean).join('/');
|
|
71
|
-
const possibleParent = `${currentPart}/layout`;
|
|
72
|
-
if (route === possibleParent) {
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
const parentChunk = nameToChunk[possibleParent];
|
|
76
|
-
if (output.has(parentChunk)) {
|
|
77
|
-
parents.push(copy(output.get(parentChunk).usedIds));
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return parents;
|
|
81
|
-
};
|
|
82
|
-
const newOutput = new Map();
|
|
83
|
-
for (const chunk of output.keys()){
|
|
84
|
-
const currentUsedIds = copy(output.get(chunk).usedIds);
|
|
85
|
-
for (const parent of getAllParentUsedIds(chunk)){
|
|
86
|
-
removeParentFromCurrent(currentUsedIds, parent);
|
|
87
|
-
}
|
|
88
|
-
newOutput.set(chunk, {
|
|
89
|
-
...output.get(chunk),
|
|
90
|
-
usedIds: currentUsedIds
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
return newOutput;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export { optimizeCSSOutput };
|