@graphcommerce/next-config 8.1.0-canary.7 → 8.1.0-canary.9
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 +32 -0
- package/Config.graphqls +5 -5
- package/__tests__/interceptors/findPlugins.ts +110 -94
- package/__tests__/interceptors/generateInterceptors.ts +111 -107
- package/__tests__/utils/resolveDependenciesSync.ts +4 -0
- package/dist/config/commands/exportConfig.js +5 -0
- package/dist/config/commands/generateConfig.js +5 -0
- package/dist/config/commands/generateIntercetors.js +9 -0
- package/dist/generated/config.js +2 -1
- package/dist/index.js +1 -0
- package/dist/interceptors/commands/codegenInterceptors.js +23 -0
- package/dist/interceptors/commands/generateIntercetors.js +9 -0
- package/dist/interceptors/findPlugins.js +7 -3
- package/dist/interceptors/generateInterceptor.js +31 -13
- package/dist/interceptors/generateInterceptors.js +6 -5
- package/dist/utils/resolveDependenciesSync.js +5 -4
- package/dist/utils/resolveDependency.js +5 -0
- package/dist/withGraphCommerce.js +1 -1
- package/package.json +1 -1
- package/src/config/commands/exportConfig.ts +3 -0
- package/src/config/commands/generateConfig.ts +3 -0
- package/src/generated/config.ts +8 -6
- package/src/index.ts +1 -0
- package/src/interceptors/commands/codegenInterceptors.ts +27 -0
- package/src/interceptors/findPlugins.ts +7 -3
- package/src/interceptors/generateInterceptor.ts +39 -13
- package/src/interceptors/generateInterceptors.ts +9 -6
- package/src/utils/resolveDependenciesSync.ts +11 -3
- package/src/utils/resolveDependency.ts +7 -0
- package/src/withGraphCommerce.ts +2 -1
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graphcommerce/next-config",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
-
"version": "8.1.0-canary.
|
|
5
|
+
"version": "8.1.0-canary.9",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"types": "src/index.ts",
|
|
@@ -2,10 +2,13 @@ import { writeFileSync } from 'fs'
|
|
|
2
2
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
3
3
|
import { generate } from '@graphql-codegen/cli'
|
|
4
4
|
import { transformFileSync } from '@swc/core'
|
|
5
|
+
import dotenv from 'dotenv'
|
|
5
6
|
import { isMonorepo } from '../../utils/isMonorepo'
|
|
6
7
|
import { resolveDependenciesSync } from '../../utils/resolveDependenciesSync'
|
|
7
8
|
import { resolveDependency } from '../../utils/resolveDependency'
|
|
8
9
|
|
|
10
|
+
dotenv.config()
|
|
11
|
+
|
|
9
12
|
const packages = [...resolveDependenciesSync().values()].filter((p) => p !== '.')
|
|
10
13
|
|
|
11
14
|
const resolve = resolveDependency()
|
package/src/generated/config.ts
CHANGED
|
@@ -365,11 +365,7 @@ export type GraphCommerceStorefrontConfig = {
|
|
|
365
365
|
googleTagmanagerId?: InputMaybe<Scalars['String']['input']>;
|
|
366
366
|
/** Add a gcms-locales header to make sure queries return in a certain language, can be an array to define fallbacks. */
|
|
367
367
|
hygraphLocales?: InputMaybe<Array<Scalars['String']['input']>>;
|
|
368
|
-
/**
|
|
369
|
-
* Specify a custom locale for to load translations. Must be lowercase valid locale.
|
|
370
|
-
*
|
|
371
|
-
* This value is also used for the Intl.
|
|
372
|
-
*/
|
|
368
|
+
/** Custom locale used to load the .po files. Must be a valid locale, also used for Intl functions. */
|
|
373
369
|
linguiLocale?: InputMaybe<Scalars['String']['input']>;
|
|
374
370
|
/**
|
|
375
371
|
* Must be a [locale string](https://www.unicode.org/reports/tr35/tr35-59/tr35.html#Identifiers) for automatic redirects to work.
|
|
@@ -388,6 +384,11 @@ export type GraphCommerceStorefrontConfig = {
|
|
|
388
384
|
* - b2b-us
|
|
389
385
|
*/
|
|
390
386
|
magentoStoreCode: Scalars['String']['input'];
|
|
387
|
+
/**
|
|
388
|
+
* Allow the site to be indexed by search engines.
|
|
389
|
+
* If false, the robots.txt file will be set to disallow all.
|
|
390
|
+
*/
|
|
391
|
+
robotsAllow?: InputMaybe<Scalars['Boolean']['input']>;
|
|
391
392
|
};
|
|
392
393
|
|
|
393
394
|
/** Options to configure which values will be replaced when a variant is selected on the product page. */
|
|
@@ -512,7 +513,8 @@ export function GraphCommerceStorefrontConfigSchema(): z.ZodObject<Properties<Gr
|
|
|
512
513
|
hygraphLocales: z.array(z.string().min(1)).nullish(),
|
|
513
514
|
linguiLocale: z.string().nullish(),
|
|
514
515
|
locale: z.string().min(1),
|
|
515
|
-
magentoStoreCode: z.string().min(1)
|
|
516
|
+
magentoStoreCode: z.string().min(1),
|
|
517
|
+
robotsAllow: z.boolean().nullish()
|
|
516
518
|
})
|
|
517
519
|
}
|
|
518
520
|
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './withGraphCommerce'
|
|
|
9
9
|
export * from './generated/config'
|
|
10
10
|
export * from './config'
|
|
11
11
|
export * from './runtimeCachingOptimizations'
|
|
12
|
+
export * from './interceptors/commands/codegenInterceptors'
|
|
12
13
|
|
|
13
14
|
export type PluginProps<P extends Record<string, unknown> = Record<string, unknown>> = P & {
|
|
14
15
|
Prev: React.FC<P>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { loadConfig } from '../../config/loadConfig'
|
|
2
|
+
import { resolveDependency } from '../../utils/resolveDependency'
|
|
3
|
+
import { findPlugins } from '../findPlugins'
|
|
4
|
+
import { generateInterceptors } from '../generateInterceptors'
|
|
5
|
+
import { writeInterceptors } from '../writeInterceptors'
|
|
6
|
+
import dotenv from 'dotenv'
|
|
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, errors] = 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
|
+
}
|
|
@@ -17,10 +17,14 @@ export function findPlugins(config: GraphCommerceConfig, cwd: string = process.c
|
|
|
17
17
|
|
|
18
18
|
const errors: string[] = []
|
|
19
19
|
const plugins: PluginConfig[] = []
|
|
20
|
-
dependencies.forEach((
|
|
21
|
-
const files = globSync(`${
|
|
20
|
+
dependencies.forEach((filePath, packageName) => {
|
|
21
|
+
const files = globSync(`${filePath}/plugins/**/*.{ts,tsx}`)
|
|
22
22
|
files.forEach((file) => {
|
|
23
|
-
|
|
23
|
+
let sourceModule = file.replace('.tsx', '').replace('.ts', '')
|
|
24
|
+
if (file.startsWith(filePath))
|
|
25
|
+
sourceModule = `${packageName}/${sourceModule.slice(filePath.length + 1)}`
|
|
26
|
+
|
|
27
|
+
if (packageName === '.' && !sourceModule.startsWith('.')) sourceModule = `./${sourceModule}`
|
|
24
28
|
|
|
25
29
|
try {
|
|
26
30
|
const ast = parseFileSync(file, { syntax: 'typescript', tsx: true })
|
|
@@ -66,24 +66,24 @@ export type Interceptor = ResolveDependencyReturn & {
|
|
|
66
66
|
|
|
67
67
|
export type MaterializedPlugin = Interceptor & { template: string }
|
|
68
68
|
|
|
69
|
-
export const SOURCE_START = '/**
|
|
70
|
-
export const SOURCE_END = '/**
|
|
69
|
+
export const SOURCE_START = '/** Original source starts here (do not modify!): **/'
|
|
70
|
+
export const SOURCE_END = '/** Original source ends here (do not modify!) **/'
|
|
71
71
|
|
|
72
72
|
const originalSuffix = 'Original'
|
|
73
|
-
const sourceSuffix = '
|
|
73
|
+
const sourceSuffix = 'Plugin'
|
|
74
74
|
const interceptorSuffix = 'Interceptor'
|
|
75
75
|
const disabledSuffix = 'Disabled'
|
|
76
76
|
const name = (plugin: PluginConfig) =>
|
|
77
|
-
`${plugin.
|
|
77
|
+
`${plugin.sourceModule
|
|
78
78
|
.split('/')
|
|
79
79
|
[plugin.sourceModule.split('/').length - 1].replace(/[^a-zA-Z0-9]/g, '')}`
|
|
80
80
|
|
|
81
81
|
const fileName = (plugin: PluginConfig) => `${plugin.sourceModule}#${plugin.sourceExport}`
|
|
82
82
|
|
|
83
83
|
const originalName = (n: string) => `${n}${originalSuffix}`
|
|
84
|
-
const sourceName = (n: string) => `${n}
|
|
84
|
+
const sourceName = (n: string) => `${n}`
|
|
85
85
|
const interceptorName = (n: string) => `${n}${interceptorSuffix}`
|
|
86
|
-
const interceptorPropsName = (n: string) => `${
|
|
86
|
+
const interceptorPropsName = (n: string) => `${n}Props`
|
|
87
87
|
|
|
88
88
|
export function moveRelativeDown(plugins: PluginConfig[]) {
|
|
89
89
|
return [...plugins].sort((a, b) => {
|
|
@@ -153,7 +153,12 @@ export async function generateInterceptor(
|
|
|
153
153
|
const duplicateInterceptors = new Set()
|
|
154
154
|
|
|
155
155
|
let carry = originalName(base)
|
|
156
|
-
|
|
156
|
+
let carryProps: string[] = []
|
|
157
|
+
const pluginSee: string[] = []
|
|
158
|
+
|
|
159
|
+
pluginSee.push(
|
|
160
|
+
`@see {@link file://${interceptor.sourcePathRelative}} for original source file`,
|
|
161
|
+
)
|
|
157
162
|
|
|
158
163
|
const pluginStr = plugins
|
|
159
164
|
.reverse()
|
|
@@ -178,14 +183,19 @@ export async function generateInterceptor(
|
|
|
178
183
|
carryProps.push(interceptorPropsName(name(p)))
|
|
179
184
|
|
|
180
185
|
result = `type ${interceptorPropsName(name(p))} = React.ComponentProps<typeof ${sourceName(name(p))}>`
|
|
186
|
+
|
|
187
|
+
pluginSee.push(
|
|
188
|
+
`@see {${sourceName(name(p))}} for replacement of the original source (original source not used)`,
|
|
189
|
+
)
|
|
181
190
|
}
|
|
182
191
|
|
|
183
192
|
if (isReactPluginConfig(p)) {
|
|
184
|
-
|
|
193
|
+
const withBraces = config.pluginStatus || process.env.NODE_ENV === 'development'
|
|
185
194
|
|
|
186
195
|
result = `
|
|
187
|
-
type ${interceptorPropsName(name(p))} =
|
|
188
|
-
|
|
196
|
+
type ${interceptorPropsName(name(p))} = ${carryProps.join(' & ')} & OmitPrev<React.ComponentProps<typeof ${sourceName(name(p))}>, 'Prev'>
|
|
197
|
+
|
|
198
|
+
const ${interceptorName(name(p))} = (props: ${interceptorPropsName(name(p))}) => ${withBraces ? `{` : '('}
|
|
189
199
|
${config.pluginStatus ? `logOnce(\`🔌 Rendering ${base} with plugin(s): ${wrapChain} wrapping <${base}/>\`)` : ''}
|
|
190
200
|
|
|
191
201
|
${
|
|
@@ -194,8 +204,11 @@ export async function generateInterceptor(
|
|
|
194
204
|
logOnce('${fileName(p)} does not spread props to prev: <Prev {...props}/>. This will cause issues if multiple plugins are applied to this component.')`
|
|
195
205
|
: ''
|
|
196
206
|
}
|
|
197
|
-
return <${sourceName(name(p))} {...props} Prev={${carry}
|
|
198
|
-
}`
|
|
207
|
+
${withBraces ? `return` : ''} <${sourceName(name(p))} {...props} Prev={${carry}} />
|
|
208
|
+
${withBraces ? `}` : ')'}`
|
|
209
|
+
|
|
210
|
+
carryProps = [interceptorPropsName(name(p))]
|
|
211
|
+
pluginSee.push(`@see {${sourceName(name(p))}} for source of applied plugin`)
|
|
199
212
|
}
|
|
200
213
|
|
|
201
214
|
if (isMethodPluginConfig(p)) {
|
|
@@ -203,6 +216,7 @@ export async function generateInterceptor(
|
|
|
203
216
|
${config.pluginStatus ? `logOnce(\`🔌 Calling ${base} with plugin(s): ${wrapChain} wrapping ${base}()\`)` : ''}
|
|
204
217
|
return ${sourceName(name(p))}(${carry}, ...args)
|
|
205
218
|
}`
|
|
219
|
+
pluginSee.push(`@see {${sourceName(name(p))}} for source of applied plugin`)
|
|
206
220
|
}
|
|
207
221
|
|
|
208
222
|
carry = p.type === 'replace' ? sourceName(name(p)) : interceptorName(name(p))
|
|
@@ -216,8 +230,18 @@ export async function generateInterceptor(
|
|
|
216
230
|
throw new Error(`Cannot mix React and Method plugins for ${base} in ${dependency}.`)
|
|
217
231
|
}
|
|
218
232
|
|
|
233
|
+
const seeString = `
|
|
234
|
+
/**
|
|
235
|
+
* Here you see the 'interceptor' that is applying all the configured plugins.
|
|
236
|
+
*
|
|
237
|
+
* This file is NOT meant to be modified directly and is auto-generated if the plugins or the original source changes.
|
|
238
|
+
*
|
|
239
|
+
${pluginSee.map((s) => `* ${s}`).join('\n')}
|
|
240
|
+
*/`
|
|
241
|
+
|
|
219
242
|
if (process.env.NODE_ENV === 'development' && isComponent) {
|
|
220
243
|
return `${pluginStr}
|
|
244
|
+
${seeString}
|
|
221
245
|
export const ${base}: typeof ${carry} = (props) => {
|
|
222
246
|
return <${carry} {...props} data-plugin />
|
|
223
247
|
}`
|
|
@@ -225,6 +249,7 @@ export async function generateInterceptor(
|
|
|
225
249
|
|
|
226
250
|
return `
|
|
227
251
|
${pluginStr}
|
|
252
|
+
${seeString}
|
|
228
253
|
export const ${base} = ${carry}
|
|
229
254
|
`
|
|
230
255
|
})
|
|
@@ -247,12 +272,13 @@ export async function generateInterceptor(
|
|
|
247
272
|
/* This file is automatically generated for ${dependency} */
|
|
248
273
|
${
|
|
249
274
|
Object.values(targetExports).some((t) => t.some((p) => p.type === 'component'))
|
|
250
|
-
? `import type { DistributedOmit } from 'type-fest'`
|
|
275
|
+
? `import type { DistributedOmit as OmitPrev } from 'type-fest'`
|
|
251
276
|
: ''
|
|
252
277
|
}
|
|
253
278
|
|
|
254
279
|
${pluginImports}
|
|
255
280
|
|
|
281
|
+
/** @see {@link file://${interceptor.sourcePathRelative}} for source of original */
|
|
256
282
|
${SOURCE_START}
|
|
257
283
|
${printSync(ast).code}
|
|
258
284
|
${SOURCE_END}
|
|
@@ -19,6 +19,7 @@ export async function generateInterceptors(
|
|
|
19
19
|
plugins: PluginConfig[],
|
|
20
20
|
resolve: ResolveDependency,
|
|
21
21
|
config?: GraphCommerceDebugConfig | null | undefined,
|
|
22
|
+
force?: boolean,
|
|
22
23
|
): Promise<GenerateInterceptorsReturn> {
|
|
23
24
|
const byTargetModuleAndExport = moveRelativeDown(plugins).reduce<Record<string, Interceptor>>(
|
|
24
25
|
(acc, plug) => {
|
|
@@ -68,12 +69,14 @@ export async function generateInterceptors(
|
|
|
68
69
|
Object.entries(byTargetModuleAndExport).map(async ([target, interceptor]) => {
|
|
69
70
|
const file = `${interceptor.fromRoot}.interceptor.tsx`
|
|
70
71
|
|
|
71
|
-
const originalSource =
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
const originalSource =
|
|
73
|
+
!force &&
|
|
74
|
+
(await fs
|
|
75
|
+
.access(file, fs.constants.F_OK)
|
|
76
|
+
.then(() => true)
|
|
77
|
+
.catch(() => false))
|
|
78
|
+
? (await fs.readFile(file)).toString()
|
|
79
|
+
: undefined
|
|
77
80
|
|
|
78
81
|
return [
|
|
79
82
|
target,
|
|
@@ -12,6 +12,7 @@ function resolveRecursivePackageJson(
|
|
|
12
12
|
dependencyPath: string,
|
|
13
13
|
dependencyStructure: DependencyStructure,
|
|
14
14
|
root: string,
|
|
15
|
+
additionalDependencies: string[] = [],
|
|
15
16
|
) {
|
|
16
17
|
const isRoot = dependencyPath === root
|
|
17
18
|
const fileName = require.resolve(path.join(dependencyPath, 'package.json'))
|
|
@@ -28,8 +29,9 @@ function resolveRecursivePackageJson(
|
|
|
28
29
|
const dependencies = [
|
|
29
30
|
...new Set(
|
|
30
31
|
[
|
|
31
|
-
...Object.keys(packageJson.dependencies ??
|
|
32
|
-
...Object.keys(packageJson.devDependencies ??
|
|
32
|
+
...Object.keys(packageJson.dependencies ?? []),
|
|
33
|
+
...Object.keys(packageJson.devDependencies ?? []),
|
|
34
|
+
...additionalDependencies,
|
|
33
35
|
// ...Object.keys(packageJson.peerDependencies ?? {}),
|
|
34
36
|
].filter((name) => name.includes('graphcommerce')),
|
|
35
37
|
),
|
|
@@ -77,7 +79,13 @@ export function sortDependencies(dependencyStructure: DependencyStructure): Pack
|
|
|
77
79
|
export function resolveDependenciesSync(root = process.cwd()) {
|
|
78
80
|
const cached = resolveCache.get(root)
|
|
79
81
|
if (cached) return cached
|
|
80
|
-
|
|
82
|
+
|
|
83
|
+
const dependencyStructure = resolveRecursivePackageJson(
|
|
84
|
+
root,
|
|
85
|
+
{},
|
|
86
|
+
root,
|
|
87
|
+
process.env.PRIVATE_ADDITIONAL_DEPENDENCIES?.split(',') ?? [],
|
|
88
|
+
)
|
|
81
89
|
|
|
82
90
|
const sorted = sortDependencies(dependencyStructure)
|
|
83
91
|
resolveCache.set(root, sorted)
|
|
@@ -11,6 +11,7 @@ export type ResolveDependencyReturn =
|
|
|
11
11
|
fromModule: string
|
|
12
12
|
source: string
|
|
13
13
|
sourcePath: string
|
|
14
|
+
sourcePathRelative: string
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export type ResolveDependency = (
|
|
@@ -31,6 +32,7 @@ export const resolveDependency = (cwd: string = process.cwd()) => {
|
|
|
31
32
|
root: '.',
|
|
32
33
|
source: '',
|
|
33
34
|
sourcePath: '',
|
|
35
|
+
sourcePathRelative: '',
|
|
34
36
|
dependency,
|
|
35
37
|
fromRoot: dependency,
|
|
36
38
|
fromModule: dependency,
|
|
@@ -73,6 +75,10 @@ export const resolveDependency = (cwd: string = process.cwd()) => {
|
|
|
73
75
|
? '.'
|
|
74
76
|
: `./${relative.split('/')[relative.split('/').length - 1]}`
|
|
75
77
|
|
|
78
|
+
const sourcePathRelative = !sourcePath
|
|
79
|
+
? '.'
|
|
80
|
+
: `./${sourcePath.split('/')[sourcePath.split('/').length - 1]}`
|
|
81
|
+
|
|
76
82
|
if (dependency.startsWith('./')) fromModule = `.${relative}`
|
|
77
83
|
|
|
78
84
|
dependencyPaths = {
|
|
@@ -83,6 +89,7 @@ export const resolveDependency = (cwd: string = process.cwd()) => {
|
|
|
83
89
|
fromModule,
|
|
84
90
|
source,
|
|
85
91
|
sourcePath,
|
|
92
|
+
sourcePathRelative,
|
|
86
93
|
}
|
|
87
94
|
}
|
|
88
95
|
})
|
package/src/withGraphCommerce.ts
CHANGED
|
@@ -121,8 +121,9 @@ export function withGraphCommerce(nextConfig: NextConfig, cwd: string): NextConf
|
|
|
121
121
|
config.plugins.push(new DefinePlugin(importMetaPaths))
|
|
122
122
|
|
|
123
123
|
// To properly properly treeshake @apollo/client we need to define the __DEV__ property
|
|
124
|
+
config.plugins.push(new DefinePlugin({ 'globalThis.__DEV__': options.dev }))
|
|
125
|
+
|
|
124
126
|
if (!options.isServer) {
|
|
125
|
-
config.plugins.push(new DefinePlugin({ __DEV__: options.dev }))
|
|
126
127
|
if (graphcommerceConfig.debug?.webpackCircularDependencyPlugin) {
|
|
127
128
|
config.plugins.push(
|
|
128
129
|
new CircularDependencyPlugin({
|