@graphcommerce/next-config 9.1.0-canary.55 → 10.0.0-canary.56
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/CHANGELOG.md +80 -0
- package/Config.graphqls +3 -3
- package/__tests__/config/utils/__snapshots__/mergeEnvIntoConfig.ts.snap +1 -1
- package/__tests__/interceptors/generateInterceptors.ts +133 -150
- package/dist/config/loadConfig.js +7 -0
- package/dist/generated/config.js +9 -9
- package/dist/index.js +804 -2436
- package/dist/loadConfig-nJiCKeL1.js +311 -0
- package/dist/utils/findParentPath.js +36 -0
- package/package.json +41 -20
- package/src/commands/cleanupInterceptors.ts +26 -0
- package/src/commands/codegen.ts +13 -15
- package/src/commands/codegenInterceptors.ts +31 -0
- package/src/{config/commands → commands}/exportConfig.ts +3 -3
- package/src/{config/commands → commands}/generateConfig.ts +12 -9
- package/src/commands/generateConfigValues.ts +265 -0
- package/src/commands/index.ts +7 -0
- package/src/config/index.ts +0 -9
- package/src/config/loadConfig.ts +0 -1
- package/src/config/utils/mergeEnvIntoConfig.ts +27 -4
- package/src/generated/config.ts +13 -14
- package/src/index.ts +7 -39
- package/src/interceptors/generateInterceptor.ts +192 -157
- package/src/interceptors/generateInterceptors.ts +9 -2
- package/src/interceptors/updatePackageExports.ts +147 -0
- package/src/interceptors/writeInterceptors.ts +90 -35
- package/src/types.ts +26 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/resolveDependenciesSync.ts +5 -7
- package/src/withGraphCommerce.ts +30 -49
- package/tsconfig.json +3 -1
- package/__tests__/config/utils/configToImportMeta.ts +0 -121
- package/src/interceptors/InterceptorPlugin.ts +0 -141
- package/src/interceptors/commands/codegenInterceptors.ts +0 -27
- /package/src/utils/{isMonorepo.ts → findParentPath.ts} +0 -0
|
@@ -1,56 +1,111 @@
|
|
|
1
|
-
|
|
1
|
+
import { stat } from 'node:fs'
|
|
2
2
|
import fs from 'node:fs/promises'
|
|
3
3
|
import path from 'path'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { glob } from 'glob'
|
|
5
|
+
import { findParentPath } from '../utils/findParentPath'
|
|
6
6
|
import type { GenerateInterceptorsReturn } from './generateInterceptors'
|
|
7
7
|
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
.access(file, fs.constants.F_OK)
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
export async function fsExists(file: string): Promise<boolean> {
|
|
9
|
+
try {
|
|
10
|
+
await fs.access(file, fs.constants.F_OK)
|
|
11
|
+
return true
|
|
12
|
+
} catch {
|
|
13
|
+
return false
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export async function fsRealpath(file: string): Promise<string> {
|
|
17
|
+
return (await fsExists(file)) ? fs.realpath(file) : file
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function restoreOriginalFile(fileWithOriginalInTheName: string): Promise<boolean> {
|
|
21
|
+
const restoredPath = fileWithOriginalInTheName.replace(/\.original\.(tsx?)$/, '.$1')
|
|
22
|
+
|
|
23
|
+
if (await fsExists(fileWithOriginalInTheName)) {
|
|
24
|
+
// Remove the current interceptor file if it exists
|
|
25
|
+
if (await fsExists(restoredPath)) {
|
|
26
|
+
await fs.unlink(restoredPath)
|
|
27
|
+
}
|
|
28
|
+
// Restore the original file
|
|
29
|
+
await fs.rename(fileWithOriginalInTheName, restoredPath)
|
|
30
|
+
return true
|
|
31
|
+
}
|
|
32
|
+
return false
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function findDotOriginalFiles(cwd: string) {
|
|
36
|
+
let parentPath = findParentPath(process.cwd())
|
|
37
|
+
while (parentPath) {
|
|
38
|
+
const p = findParentPath(parentPath)
|
|
39
|
+
if (p) parentPath = p
|
|
40
|
+
else break
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return Promise.all(
|
|
44
|
+
(
|
|
45
|
+
await glob([`${parentPath}/**/*.original.tsx`, `${parentPath}/**/*.original.ts`], { cwd })
|
|
46
|
+
).map((file) => fs.realpath(file)),
|
|
47
|
+
)
|
|
13
48
|
}
|
|
14
49
|
|
|
15
50
|
export async function writeInterceptors(
|
|
16
51
|
interceptors: GenerateInterceptorsReturn,
|
|
17
52
|
cwd: string = process.cwd(),
|
|
18
53
|
) {
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
dependencies.forEach((dependency) => {
|
|
22
|
-
const files = globSync(
|
|
23
|
-
[`${dependency}/**/*.interceptor.tsx`, `${dependency}/**/*.interceptor.ts`],
|
|
24
|
-
{ cwd },
|
|
25
|
-
)
|
|
26
|
-
files.forEach((file) => existing.add(file))
|
|
27
|
-
})
|
|
54
|
+
const processedFiles: string[] = []
|
|
55
|
+
const existingDotOriginalFiles = findDotOriginalFiles(cwd)
|
|
28
56
|
|
|
57
|
+
// Process each interceptor
|
|
29
58
|
const written = Object.entries(interceptors).map(async ([, plugin]) => {
|
|
30
59
|
const extension = plugin.sourcePath.endsWith('.tsx') ? '.tsx' : '.ts'
|
|
31
|
-
const relativeFile = `${plugin.fromRoot}.interceptor${extension}`
|
|
32
60
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
existing.delete(`./${relativeFile}`)
|
|
38
|
-
}
|
|
61
|
+
const targetFileName = `${plugin.fromRoot}${extension}`
|
|
62
|
+
const fileNameDotOriginal = `${plugin.fromRoot}.original${extension}`
|
|
63
|
+
const targetFilePath = await fsRealpath(path.resolve(cwd, targetFileName))
|
|
64
|
+
const dotOriginalPath = await fsRealpath(path.resolve(cwd, fileNameDotOriginal))
|
|
39
65
|
|
|
40
|
-
|
|
66
|
+
processedFiles.push(dotOriginalPath)
|
|
41
67
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
68
|
+
const targetSource = (await fsExists(targetFilePath))
|
|
69
|
+
? await fs.readFile(targetFilePath, 'utf8')
|
|
70
|
+
: null
|
|
45
71
|
|
|
46
|
-
|
|
47
|
-
|
|
72
|
+
const dotOriginalSource = (await fsExists(dotOriginalPath))
|
|
73
|
+
? await fs.readFile(dotOriginalPath, 'utf8')
|
|
74
|
+
: null
|
|
48
75
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
76
|
+
const isPreviouslyApplied = dotOriginalSource !== null && targetSource?.includes('/* hash:')
|
|
77
|
+
|
|
78
|
+
let status = ''
|
|
79
|
+
if (isPreviouslyApplied) {
|
|
80
|
+
if (targetSource === plugin.template) {
|
|
81
|
+
status = '✅ Unchanged interceptor'
|
|
82
|
+
} else {
|
|
83
|
+
status = '🔄 Updating interceptor'
|
|
84
|
+
await fs.writeFile(targetFilePath, plugin.template)
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
status = '🆕 Creating interceptor'
|
|
88
|
+
await fs.rename(targetFilePath, dotOriginalPath)
|
|
89
|
+
await fs.writeFile(targetFilePath, plugin.template)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log(`${status} ${plugin.dependency}`)
|
|
93
|
+
Object.entries(plugin.targetExports).forEach(([target, plugins]) => {
|
|
94
|
+
plugins.forEach((plugin) => {
|
|
95
|
+
console.log(` 🔌 ${target} <- ${plugin.sourceModule}`)
|
|
96
|
+
})
|
|
97
|
+
})
|
|
98
|
+
})
|
|
53
99
|
|
|
54
100
|
await Promise.all(written)
|
|
55
|
-
|
|
101
|
+
|
|
102
|
+
const toRestore = (await existingDotOriginalFiles).filter(
|
|
103
|
+
(file) => !processedFiles.includes(file),
|
|
104
|
+
)
|
|
105
|
+
await Promise.all(
|
|
106
|
+
toRestore.map((file) => {
|
|
107
|
+
console.log(`↩ Removing old interceptor ${file}`)
|
|
108
|
+
return restoreOriginalFile(file)
|
|
109
|
+
}),
|
|
110
|
+
)
|
|
56
111
|
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type React from 'react'
|
|
2
|
+
import type { Path, PathValue } from 'react-hook-form'
|
|
3
|
+
import type { GraphCommerceConfig } from './generated/config'
|
|
4
|
+
|
|
5
|
+
export type PluginProps<P extends Record<string, unknown> = Record<string, unknown>> = P & {
|
|
6
|
+
Prev: React.FC<P>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type FunctionPlugin<T extends (...args: any[]) => any> = (
|
|
10
|
+
prev: T,
|
|
11
|
+
...args: Parameters<T>
|
|
12
|
+
) => ReturnType<T>
|
|
13
|
+
|
|
14
|
+
/** @deprecated Use FunctionPlugin instead */
|
|
15
|
+
export type MethodPlugin<T extends (...args: any[]) => any> = (
|
|
16
|
+
prev: T,
|
|
17
|
+
...args: Parameters<T>
|
|
18
|
+
) => ReturnType<T>
|
|
19
|
+
|
|
20
|
+
export type PluginConfig<P extends Path<GraphCommerceConfig> = Path<GraphCommerceConfig>> = {
|
|
21
|
+
type: PluginType
|
|
22
|
+
module: string
|
|
23
|
+
ifConfig?: P | [P, PathValue<GraphCommerceConfig, P>]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type PluginType = 'component' | 'function' | 'replace'
|
|
@@ -10,7 +10,10 @@ type DependencyStructure = Record<string, { dirName: string; dependencies: strin
|
|
|
10
10
|
const resolveCache: Map<string, PackageNames> = new Map<string, PackageNames>()
|
|
11
11
|
|
|
12
12
|
function findPackageJson(id: string, root: string) {
|
|
13
|
-
let dir = id.startsWith('/') ? id :
|
|
13
|
+
let dir = id.startsWith('/') ? id : import.meta.resolve(id)
|
|
14
|
+
|
|
15
|
+
if (dir.startsWith('file://')) dir = new URL(dir).pathname
|
|
16
|
+
|
|
14
17
|
let packageJsonLocation = path.join(dir, 'package.json')
|
|
15
18
|
while (!fs.existsSync(packageJsonLocation)) {
|
|
16
19
|
dir = path.dirname(dir)
|
|
@@ -28,12 +31,7 @@ function resolveRecursivePackageJson(
|
|
|
28
31
|
) {
|
|
29
32
|
const isRoot = dependencyPath === root
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
fileName = require.resolve(path.join(dependencyPath, 'package.json'))
|
|
34
|
-
} catch (e) {
|
|
35
|
-
fileName = findPackageJson(dependencyPath, root)
|
|
36
|
-
}
|
|
34
|
+
const fileName = findPackageJson(dependencyPath, root)
|
|
37
35
|
if (!fileName) throw Error(`Can't find package.json for ${dependencyPath}`)
|
|
38
36
|
|
|
39
37
|
const packageJsonFile = fs.readFileSync(fileName, 'utf-8').toString()
|
package/src/withGraphCommerce.ts
CHANGED
|
@@ -3,11 +3,8 @@
|
|
|
3
3
|
import type { NextConfig } from 'next'
|
|
4
4
|
import type { DomainLocale } from 'next/dist/server/config'
|
|
5
5
|
import type { Configuration } from 'webpack'
|
|
6
|
-
import webpack from 'webpack'
|
|
7
6
|
import { loadConfig } from './config/loadConfig'
|
|
8
|
-
import { configToImportMeta } from './config/utils/configToImportMeta'
|
|
9
7
|
import type { GraphCommerceConfig } from './generated/config'
|
|
10
|
-
import { InterceptorPlugin } from './interceptors/InterceptorPlugin'
|
|
11
8
|
import { resolveDependenciesSync } from './utils/resolveDependenciesSync'
|
|
12
9
|
|
|
13
10
|
let graphcommerceConfig: GraphCommerceConfig
|
|
@@ -33,7 +30,7 @@ function domains(config: GraphCommerceConfig): DomainLocale[] {
|
|
|
33
30
|
}
|
|
34
31
|
|
|
35
32
|
/**
|
|
36
|
-
* GraphCommerce configuration
|
|
33
|
+
* GraphCommerce configuration with new Turbopack-compatible interceptor system.
|
|
37
34
|
*
|
|
38
35
|
* ```ts
|
|
39
36
|
* const { withGraphCommerce } = require('@graphcommerce/next-config')
|
|
@@ -43,7 +40,6 @@ function domains(config: GraphCommerceConfig): DomainLocale[] {
|
|
|
43
40
|
*/
|
|
44
41
|
export function withGraphCommerce(nextConfig: NextConfig, cwd: string = process.cwd()): NextConfig {
|
|
45
42
|
graphcommerceConfig ??= loadConfig(cwd)
|
|
46
|
-
const importMetaPaths = configToImportMeta(graphcommerceConfig)
|
|
47
43
|
|
|
48
44
|
const { storefront } = graphcommerceConfig
|
|
49
45
|
|
|
@@ -55,10 +51,36 @@ export function withGraphCommerce(nextConfig: NextConfig, cwd: string = process.
|
|
|
55
51
|
return {
|
|
56
52
|
...nextConfig,
|
|
57
53
|
bundlePagesRouterDependencies: true,
|
|
54
|
+
serverExternalPackages: [
|
|
55
|
+
// All @whatwg-node packages to prevent private class field bundling issues
|
|
56
|
+
// https://github.com/ardatan/whatwg-node/tree/master/packages
|
|
57
|
+
'@whatwg-node/cookie-store',
|
|
58
|
+
'@whatwg-node/disposablestack',
|
|
59
|
+
'@whatwg-node/events',
|
|
60
|
+
'@whatwg-node/fetch',
|
|
61
|
+
'@whatwg-node/node-fetch',
|
|
62
|
+
'@whatwg-node/promise-helpers',
|
|
63
|
+
'@whatwg-node/server',
|
|
64
|
+
'@whatwg-node/server-plugin-cookies',
|
|
65
|
+
...(nextConfig.serverExternalPackages ?? []),
|
|
66
|
+
],
|
|
67
|
+
turbopack: {
|
|
68
|
+
...(nextConfig.turbopack ?? {}),
|
|
69
|
+
rules: {
|
|
70
|
+
...(nextConfig.turbopack?.rules ?? {}),
|
|
71
|
+
'*.yaml': { loaders: [{ loader: 'js-yaml-loader', options: {} }], as: '*.js' },
|
|
72
|
+
'*.yml': { loaders: [{ loader: 'js-yaml-loader', options: {} }], as: '*.js' },
|
|
73
|
+
'*.po': { loaders: [{ loader: '@lingui/loader', options: {} }], as: '*.js' },
|
|
74
|
+
},
|
|
75
|
+
},
|
|
58
76
|
experimental: {
|
|
59
77
|
...nextConfig.experimental,
|
|
60
78
|
scrollRestoration: true,
|
|
61
79
|
swcPlugins: [...(nextConfig.experimental?.swcPlugins ?? []), ['@lingui/swc-plugin', {}]],
|
|
80
|
+
optimizePackageImports: [
|
|
81
|
+
...transpilePackages,
|
|
82
|
+
...(nextConfig.experimental?.optimizePackageImports ?? []),
|
|
83
|
+
],
|
|
62
84
|
},
|
|
63
85
|
i18n: {
|
|
64
86
|
...nextConfig.i18n,
|
|
@@ -69,6 +91,8 @@ export function withGraphCommerce(nextConfig: NextConfig, cwd: string = process.
|
|
|
69
91
|
},
|
|
70
92
|
images: {
|
|
71
93
|
...nextConfig.images,
|
|
94
|
+
// GraphCommerce uses quality 52 by default for optimized image delivery
|
|
95
|
+
qualities: [52, 75, ...(nextConfig.images?.qualities ?? [])],
|
|
72
96
|
remotePatterns: [
|
|
73
97
|
'magentoEndpoint' in graphcommerceConfig
|
|
74
98
|
? {
|
|
@@ -92,7 +116,7 @@ export function withGraphCommerce(nextConfig: NextConfig, cwd: string = process.
|
|
|
92
116
|
typeof graphcommerceConfig.productRoute === 'string' &&
|
|
93
117
|
graphcommerceConfig.productRoute !== '/p/'
|
|
94
118
|
) {
|
|
95
|
-
rewrites.beforeFiles
|
|
119
|
+
rewrites.beforeFiles?.push({
|
|
96
120
|
source: `${graphcommerceConfig.productRoute ?? '/p/'}:path*`,
|
|
97
121
|
destination: '/p/:path*',
|
|
98
122
|
})
|
|
@@ -118,37 +142,6 @@ export function withGraphCommerce(nextConfig: NextConfig, cwd: string = process.
|
|
|
118
142
|
|
|
119
143
|
if (!config.plugins) config.plugins = []
|
|
120
144
|
|
|
121
|
-
// Make import.meta.graphCommerce available for usage.
|
|
122
|
-
config.plugins.push(new webpack.DefinePlugin(importMetaPaths))
|
|
123
|
-
|
|
124
|
-
// To properly properly treeshake @apollo/client we need to define the __DEV__ property
|
|
125
|
-
config.plugins.push(new webpack.DefinePlugin({ 'globalThis.__DEV__': options.dev }))
|
|
126
|
-
|
|
127
|
-
if (!options.isServer) {
|
|
128
|
-
// if (graphcommerceConfig.debug?.webpackCircularDependencyPlugin) {
|
|
129
|
-
// config.plugins.push(
|
|
130
|
-
// new CircularDependencyPlugin({
|
|
131
|
-
// exclude: /readable-stream|duplexer2|node_modules\/next/,
|
|
132
|
-
// }),
|
|
133
|
-
// )
|
|
134
|
-
// }
|
|
135
|
-
// if (graphcommerceConfig.debug?.webpackDuplicatesPlugin) {
|
|
136
|
-
// config.plugins.push(
|
|
137
|
-
// new DuplicatesPlugin({
|
|
138
|
-
// ignoredPackages: [
|
|
139
|
-
// // very small
|
|
140
|
-
// 'react-is',
|
|
141
|
-
// // build issue
|
|
142
|
-
// 'tslib',
|
|
143
|
-
// // server
|
|
144
|
-
// 'isarray',
|
|
145
|
-
// 'readable-stream',
|
|
146
|
-
// ],
|
|
147
|
-
// }),
|
|
148
|
-
// )
|
|
149
|
-
// }
|
|
150
|
-
}
|
|
151
|
-
|
|
152
145
|
config.snapshot = {
|
|
153
146
|
...(config.snapshot ?? {}),
|
|
154
147
|
managedPaths: [
|
|
@@ -166,18 +159,6 @@ export function withGraphCommerce(nextConfig: NextConfig, cwd: string = process.
|
|
|
166
159
|
}
|
|
167
160
|
|
|
168
161
|
if (!config.resolve) config.resolve = {}
|
|
169
|
-
if (!options.isServer && !options.dev) {
|
|
170
|
-
config.resolve.alias = {
|
|
171
|
-
...config.resolve.alias,
|
|
172
|
-
'@mui/base': '@mui/base/modern',
|
|
173
|
-
'@mui/lab': '@mui/lab/modern',
|
|
174
|
-
'@mui/material': '@mui/material/modern',
|
|
175
|
-
'@mui/styled-engine': '@mui/styled-engine/modern',
|
|
176
|
-
'@mui/system': '@mui/system/modern',
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
config.plugins.push(new InterceptorPlugin(graphcommerceConfig, !options.isServer))
|
|
181
162
|
|
|
182
163
|
return typeof nextConfig.webpack === 'function' ? nextConfig.webpack(config, options) : config
|
|
183
164
|
},
|
package/tsconfig.json
CHANGED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { configToImportMeta } from '../../../src/config/utils/configToImportMeta'
|
|
2
|
-
const configFile = {
|
|
3
|
-
storefront: [{ locale: 'en', hygraphLocales: ['en'], magentoStoreCode: 'en_us' }],
|
|
4
|
-
demoMode: true,
|
|
5
|
-
googleTagmanagerKey: 'GTM-XXXXXXX',
|
|
6
|
-
productFiltersPro: false,
|
|
7
|
-
deeper: { arrayvalue: ['test'], nested: { value: 'test' } },
|
|
8
|
-
}
|
|
9
|
-
it('flattens a config object', () => {
|
|
10
|
-
expect(configToImportMeta(configFile)).toMatchInlineSnapshot(
|
|
11
|
-
`
|
|
12
|
-
{
|
|
13
|
-
"import.meta.graphCommerce": "{ __debug: "'import.meta.graphCommerce' can not be destructured, please access deeper properties directly" }",
|
|
14
|
-
"import.meta.graphCommerce.deeper": "{ __debug: "'import.meta.graphCommerce.deeper' can not be destructured, please access deeper properties directly" }",
|
|
15
|
-
"import.meta.graphCommerce.deeper.arrayvalue": "["test"]",
|
|
16
|
-
"import.meta.graphCommerce.deeper.nested": "{ __debug: "'import.meta.graphCommerce.deeper.nested' can not be destructured, please access deeper properties directly" }",
|
|
17
|
-
"import.meta.graphCommerce.deeper.nested.value": ""test"",
|
|
18
|
-
"import.meta.graphCommerce.deeper.nested?.value": ""test"",
|
|
19
|
-
"import.meta.graphCommerce.deeper?.arrayvalue": "["test"]",
|
|
20
|
-
"import.meta.graphCommerce.deeper?.nested": "{ __debug: "'import.meta.graphCommerce.deeper?.nested' can not be destructured, please access deeper properties directly" }",
|
|
21
|
-
"import.meta.graphCommerce.deeper?.nested.value": ""test"",
|
|
22
|
-
"import.meta.graphCommerce.deeper?.nested?.value": ""test"",
|
|
23
|
-
"import.meta.graphCommerce.demoMode": "true",
|
|
24
|
-
"import.meta.graphCommerce.googleTagmanagerKey": ""GTM-XXXXXXX"",
|
|
25
|
-
"import.meta.graphCommerce.productFiltersPro": "false",
|
|
26
|
-
"import.meta.graphCommerce.storefront": "[{"locale":"en","hygraphLocales":["en"],"magentoStoreCode":"en_us"}]",
|
|
27
|
-
"import.meta.graphCommerce?.deeper": "{ __debug: "'import.meta.graphCommerce?.deeper' can not be destructured, please access deeper properties directly" }",
|
|
28
|
-
"import.meta.graphCommerce?.deeper.arrayvalue": "["test"]",
|
|
29
|
-
"import.meta.graphCommerce?.deeper.nested": "{ __debug: "'import.meta.graphCommerce?.deeper.nested' can not be destructured, please access deeper properties directly" }",
|
|
30
|
-
"import.meta.graphCommerce?.deeper.nested.value": ""test"",
|
|
31
|
-
"import.meta.graphCommerce?.deeper.nested?.value": ""test"",
|
|
32
|
-
"import.meta.graphCommerce?.deeper?.arrayvalue": "["test"]",
|
|
33
|
-
"import.meta.graphCommerce?.deeper?.nested": "{ __debug: "'import.meta.graphCommerce?.deeper?.nested' can not be destructured, please access deeper properties directly" }",
|
|
34
|
-
"import.meta.graphCommerce?.deeper?.nested.value": ""test"",
|
|
35
|
-
"import.meta.graphCommerce?.deeper?.nested?.value": ""test"",
|
|
36
|
-
"import.meta.graphCommerce?.demoMode": "true",
|
|
37
|
-
"import.meta.graphCommerce?.googleTagmanagerKey": ""GTM-XXXXXXX"",
|
|
38
|
-
"import.meta.graphCommerce?.productFiltersPro": "false",
|
|
39
|
-
"import.meta.graphCommerce?.storefront": "[{"locale":"en","hygraphLocales":["en"],"magentoStoreCode":"en_us"}]",
|
|
40
|
-
}
|
|
41
|
-
`,
|
|
42
|
-
)
|
|
43
|
-
})
|
|
44
|
-
it('creates keys but does not stringify values', () => {
|
|
45
|
-
expect(configToImportMeta(configFile, 'graphCommerce', false)).toMatchInlineSnapshot(
|
|
46
|
-
`
|
|
47
|
-
{
|
|
48
|
-
"graphCommerce": {
|
|
49
|
-
"deeper": {
|
|
50
|
-
"arrayvalue": [
|
|
51
|
-
"test",
|
|
52
|
-
],
|
|
53
|
-
"nested": {
|
|
54
|
-
"value": "test",
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
"demoMode": true,
|
|
58
|
-
"googleTagmanagerKey": "GTM-XXXXXXX",
|
|
59
|
-
"productFiltersPro": false,
|
|
60
|
-
"storefront": [
|
|
61
|
-
{
|
|
62
|
-
"hygraphLocales": [
|
|
63
|
-
"en",
|
|
64
|
-
],
|
|
65
|
-
"locale": "en",
|
|
66
|
-
"magentoStoreCode": "en_us",
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
},
|
|
70
|
-
"graphCommerce.deeper": {
|
|
71
|
-
"arrayvalue": [
|
|
72
|
-
"test",
|
|
73
|
-
],
|
|
74
|
-
"nested": {
|
|
75
|
-
"value": "test",
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
"graphCommerce.deeper.arrayvalue": "["test"]",
|
|
79
|
-
"graphCommerce.deeper.nested": {
|
|
80
|
-
"value": "test",
|
|
81
|
-
},
|
|
82
|
-
"graphCommerce.deeper.nested.value": "test",
|
|
83
|
-
"graphCommerce.deeper.nested?.value": "test",
|
|
84
|
-
"graphCommerce.deeper?.arrayvalue": "["test"]",
|
|
85
|
-
"graphCommerce.deeper?.nested": {
|
|
86
|
-
"value": "test",
|
|
87
|
-
},
|
|
88
|
-
"graphCommerce.deeper?.nested.value": "test",
|
|
89
|
-
"graphCommerce.deeper?.nested?.value": "test",
|
|
90
|
-
"graphCommerce.demoMode": true,
|
|
91
|
-
"graphCommerce.googleTagmanagerKey": "GTM-XXXXXXX",
|
|
92
|
-
"graphCommerce.productFiltersPro": false,
|
|
93
|
-
"graphCommerce.storefront": "[{"locale":"en","hygraphLocales":["en"],"magentoStoreCode":"en_us"}]",
|
|
94
|
-
"graphCommerce?.deeper": {
|
|
95
|
-
"arrayvalue": [
|
|
96
|
-
"test",
|
|
97
|
-
],
|
|
98
|
-
"nested": {
|
|
99
|
-
"value": "test",
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
"graphCommerce?.deeper.arrayvalue": "["test"]",
|
|
103
|
-
"graphCommerce?.deeper.nested": {
|
|
104
|
-
"value": "test",
|
|
105
|
-
},
|
|
106
|
-
"graphCommerce?.deeper.nested.value": "test",
|
|
107
|
-
"graphCommerce?.deeper.nested?.value": "test",
|
|
108
|
-
"graphCommerce?.deeper?.arrayvalue": "["test"]",
|
|
109
|
-
"graphCommerce?.deeper?.nested": {
|
|
110
|
-
"value": "test",
|
|
111
|
-
},
|
|
112
|
-
"graphCommerce?.deeper?.nested.value": "test",
|
|
113
|
-
"graphCommerce?.deeper?.nested?.value": "test",
|
|
114
|
-
"graphCommerce?.demoMode": true,
|
|
115
|
-
"graphCommerce?.googleTagmanagerKey": "GTM-XXXXXXX",
|
|
116
|
-
"graphCommerce?.productFiltersPro": false,
|
|
117
|
-
"graphCommerce?.storefront": "[{"locale":"en","hygraphLocales":["en"],"magentoStoreCode":"en_us"}]",
|
|
118
|
-
}
|
|
119
|
-
`,
|
|
120
|
-
)
|
|
121
|
-
})
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import type { Compiler } from 'webpack'
|
|
3
|
-
import type { GraphCommerceConfig } from '../generated/config'
|
|
4
|
-
import type { ResolveDependency } from '../utils/resolveDependency'
|
|
5
|
-
import { resolveDependency } from '../utils/resolveDependency'
|
|
6
|
-
import { findPlugins } from './findPlugins'
|
|
7
|
-
import type { GenerateInterceptorsReturn } from './generateInterceptors'
|
|
8
|
-
import { generateInterceptors } from './generateInterceptors'
|
|
9
|
-
import { writeInterceptors } from './writeInterceptors'
|
|
10
|
-
|
|
11
|
-
let interceptors: GenerateInterceptorsReturn | undefined
|
|
12
|
-
let interceptorByDepependency: GenerateInterceptorsReturn | undefined
|
|
13
|
-
|
|
14
|
-
let generating = false
|
|
15
|
-
|
|
16
|
-
// let totalGenerationTime = 0
|
|
17
|
-
|
|
18
|
-
export class InterceptorPlugin {
|
|
19
|
-
private resolveDependency: ResolveDependency
|
|
20
|
-
|
|
21
|
-
constructor(
|
|
22
|
-
private config: GraphCommerceConfig,
|
|
23
|
-
private regenerate: boolean = false,
|
|
24
|
-
) {
|
|
25
|
-
this.resolveDependency = resolveDependency()
|
|
26
|
-
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
28
|
-
if (regenerate) this.#generateInterceptors()
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
#generateInterceptors = async () => {
|
|
32
|
-
if (generating) return {}
|
|
33
|
-
generating = true
|
|
34
|
-
// const start = Date.now()
|
|
35
|
-
|
|
36
|
-
// console.log('Generating interceptors...')
|
|
37
|
-
|
|
38
|
-
const [plugins] = findPlugins(this.config)
|
|
39
|
-
|
|
40
|
-
// console.log(errors)
|
|
41
|
-
|
|
42
|
-
// const found = Date.now()
|
|
43
|
-
// console.log('Found plugins in', found - start, 'ms')
|
|
44
|
-
|
|
45
|
-
const generatedInterceptors = await generateInterceptors(
|
|
46
|
-
plugins,
|
|
47
|
-
this.resolveDependency,
|
|
48
|
-
this.config.debug,
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
// const generated = Date.now()
|
|
52
|
-
// console.log('Generated interceptors in', generated - found, 'ms')
|
|
53
|
-
|
|
54
|
-
await writeInterceptors(generatedInterceptors)
|
|
55
|
-
|
|
56
|
-
// const wrote = Date.now()
|
|
57
|
-
// console.log('Wrote interceptors in', wrote - generated, 'ms')
|
|
58
|
-
|
|
59
|
-
interceptors = generatedInterceptors
|
|
60
|
-
|
|
61
|
-
interceptorByDepependency = Object.fromEntries(
|
|
62
|
-
Object.values(interceptors).map((i) => [i.dependency, i]),
|
|
63
|
-
)
|
|
64
|
-
|
|
65
|
-
// totalGenerationTime += Date.now() - start
|
|
66
|
-
generating = false
|
|
67
|
-
|
|
68
|
-
return generatedInterceptors
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** @public */
|
|
72
|
-
apply(compiler: Compiler): void {
|
|
73
|
-
const logger = compiler.getInfrastructureLogger('InterceptorPlugin')
|
|
74
|
-
|
|
75
|
-
// After the compilation has succeeded we watch all possible plugin locations.
|
|
76
|
-
if (this.regenerate) {
|
|
77
|
-
compiler.hooks.afterCompile.tap('InterceptorPlugin', (compilation) => {
|
|
78
|
-
// console.log('generate interceptors after compile')
|
|
79
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
80
|
-
const [plugins, errors] = findPlugins(this.config)
|
|
81
|
-
|
|
82
|
-
plugins.forEach((p) => {
|
|
83
|
-
const source = this.resolveDependency(p.sourceModule)
|
|
84
|
-
if (source) {
|
|
85
|
-
const absoluteFilePath = `${path.join(process.cwd(), source.fromRoot)}.tsx`
|
|
86
|
-
compilation.fileDependencies.add(absoluteFilePath)
|
|
87
|
-
}
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
91
|
-
this.#generateInterceptors().then((i) => {
|
|
92
|
-
Object.entries(i).forEach(([, { sourcePath }]) => {
|
|
93
|
-
const absoluteFilePath = path.join(process.cwd(), sourcePath)
|
|
94
|
-
compilation.fileDependencies.add(absoluteFilePath)
|
|
95
|
-
})
|
|
96
|
-
})
|
|
97
|
-
})
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
compiler.hooks.normalModuleFactory.tap('InterceptorPlugin', (nmf) => {
|
|
101
|
-
nmf.hooks.beforeResolve.tap('InterceptorPlugin', (resource) => {
|
|
102
|
-
const issuer = resource.contextInfo.issuer ?? ''
|
|
103
|
-
|
|
104
|
-
const requestPath = path.relative(
|
|
105
|
-
process.cwd(),
|
|
106
|
-
path.resolve(resource.context, resource.request),
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
if (!interceptors || !interceptorByDepependency) {
|
|
110
|
-
// console.log('interceptors not ready')
|
|
111
|
-
return
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const split = requestPath.split('/')
|
|
115
|
-
const targets = [
|
|
116
|
-
`${split[split.length - 1]}.interceptor.tsx`,
|
|
117
|
-
`${split[split.length - 1]}.interceptor.ts`,
|
|
118
|
-
]
|
|
119
|
-
|
|
120
|
-
if (targets.some((target) => issuer.endsWith(target)) && interceptors[requestPath]) {
|
|
121
|
-
logger.log(`Interceptor ${issuer} is requesting the original ${requestPath}`)
|
|
122
|
-
return
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const interceptorForRequest = interceptorByDepependency[resource.request]
|
|
126
|
-
if (interceptorForRequest) {
|
|
127
|
-
const extension = interceptorForRequest.sourcePath.endsWith('.tsx') ? '.tsx' : '.ts'
|
|
128
|
-
resource.request = `${interceptorForRequest.denormalized}.interceptor${extension}`
|
|
129
|
-
logger.log(`Intercepting dep... ${interceptorForRequest.dependency}`, resource.request)
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const interceptorForPath = interceptors[requestPath]
|
|
133
|
-
if (interceptorForPath) {
|
|
134
|
-
const extension = interceptorForPath.sourcePath.endsWith('.tsx') ? '.tsx' : '.ts'
|
|
135
|
-
resource.request = `${resource.request}.interceptor${extension}`
|
|
136
|
-
logger.log(`Intercepting fromRoot... ${interceptorForPath.dependency}`, resource.request)
|
|
137
|
-
}
|
|
138
|
-
})
|
|
139
|
-
})
|
|
140
|
-
}
|
|
141
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import dotenv from 'dotenv'
|
|
2
|
-
import { loadConfig } from '../../config/loadConfig'
|
|
3
|
-
import { resolveDependency } from '../../utils/resolveDependency'
|
|
4
|
-
import { findPlugins } from '../findPlugins'
|
|
5
|
-
import { generateInterceptors } from '../generateInterceptors'
|
|
6
|
-
import { writeInterceptors } from '../writeInterceptors'
|
|
7
|
-
|
|
8
|
-
dotenv.config()
|
|
9
|
-
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
11
|
-
export async function codegenInterceptors() {
|
|
12
|
-
const conf = loadConfig(process.cwd())
|
|
13
|
-
|
|
14
|
-
const [plugins] = findPlugins(conf)
|
|
15
|
-
|
|
16
|
-
const generatedInterceptors = await generateInterceptors(
|
|
17
|
-
plugins,
|
|
18
|
-
resolveDependency(),
|
|
19
|
-
conf.debug,
|
|
20
|
-
true,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
// const generated = Date.now()
|
|
24
|
-
// console.log('Generated interceptors in', generated - found, 'ms')
|
|
25
|
-
|
|
26
|
-
await writeInterceptors(generatedInterceptors)
|
|
27
|
-
}
|
|
File without changes
|