@keak/sdk 1.0.8 → 2.0.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/dist/Conversion.d.ts.map +1 -1
- package/dist/KeakToolbarShadow.d.ts +21 -0
- package/dist/KeakToolbarShadow.d.ts.map +1 -0
- package/dist/index.cjs.js +199 -187
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +54 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +201 -187
- package/dist/index.js.map +1 -1
- package/dist/services/telemetry/index.d.ts +20 -0
- package/dist/services/telemetry/index.d.ts.map +1 -0
- package/dist/services/telemetry/telemetryService.d.ts +66 -0
- package/dist/services/telemetry/telemetryService.d.ts.map +1 -0
- package/dist/services/telemetry/types.d.ts +64 -0
- package/dist/services/telemetry/types.d.ts.map +1 -0
- package/dist/toolbar/KeakToolbar.d.ts.map +1 -1
- package/dist/toolbar/components/ui/Badge.d.ts +1 -1
- package/dist/toolbar/components/ui/Button.d.ts +2 -2
- package/dist/toolbar.js +41 -0
- package/dist/toolbar.js.map +1 -1
- package/package.json +3 -13
- package/src/cli/install.js +8 -8
- package/src/plugins/babel-source-inject.cjs +55 -131
- package/src/plugins/next.cjs +48 -221
- package/src/plugins/webpack-loader-babel/index.js +43 -117
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keak/sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Production-ready A/B testing and experimentation SDK for React applications with visual editing, source mapping, and real-time variant testing",
|
|
5
5
|
"author": "Keak Team",
|
|
6
6
|
"homepage": "https://www.keak.com/",
|
|
@@ -27,11 +27,6 @@
|
|
|
27
27
|
"import": "./dist/toolbar.js",
|
|
28
28
|
"default": "./dist/toolbar.js"
|
|
29
29
|
},
|
|
30
|
-
"./toolbar/KeakToolbarNew": {
|
|
31
|
-
"types": "./dist/toolbar/KeakToolbarNew.d.ts",
|
|
32
|
-
"import": "./dist/toolbar/KeakToolbarNew.js",
|
|
33
|
-
"default": "./dist/toolbar/KeakToolbarNew.js"
|
|
34
|
-
},
|
|
35
30
|
"./toolbar.css": "./dist/toolbar.css",
|
|
36
31
|
"./keak-toolbar.css": "./dist/keak-toolbar.css",
|
|
37
32
|
"./plugins/next": "./src/plugins/next.cjs",
|
|
@@ -80,14 +75,9 @@
|
|
|
80
75
|
}
|
|
81
76
|
},
|
|
82
77
|
"dependencies": {
|
|
83
|
-
"@
|
|
84
|
-
"@
|
|
85
|
-
"@radix-ui/react-progress": "^1.1.7",
|
|
86
|
-
"@radix-ui/react-slot": "^1.2.3",
|
|
87
|
-
"@supabase/supabase-js": "^2.86.0",
|
|
88
|
-
"class-variance-authority": "^0.7.1",
|
|
78
|
+
"@babel/parser": "^7.26.3",
|
|
79
|
+
"@babel/traverse": "^7.26.5",
|
|
89
80
|
"clsx": "^2.1.1",
|
|
90
|
-
"framer-motion": "^12.23.12",
|
|
91
81
|
"lucide-react": "^0.542.0",
|
|
92
82
|
"tailwind-merge": "^3.3.1",
|
|
93
83
|
"tw-animate-css": "^1.3.8"
|
package/src/cli/install.js
CHANGED
|
@@ -342,7 +342,7 @@ class KeakInstaller {
|
|
|
342
342
|
if (bodyMatch) {
|
|
343
343
|
const bodyContent = bodyMatch[2].trim();
|
|
344
344
|
const wrapped = `${bodyMatch[1]}
|
|
345
|
-
<KeakProvider
|
|
345
|
+
<KeakProvider>
|
|
346
346
|
${bodyContent}
|
|
347
347
|
<KeakToolbar />
|
|
348
348
|
</KeakProvider>
|
|
@@ -371,7 +371,7 @@ ${bodyContent}
|
|
|
371
371
|
const componentMatch = modified.match(/(return\s*\(?\s*)([\s\S]*?)(\s*\)?;?\s*})/);
|
|
372
372
|
if (componentMatch) {
|
|
373
373
|
const wrapped = `${componentMatch[1]}
|
|
374
|
-
<KeakProvider
|
|
374
|
+
<KeakProvider>
|
|
375
375
|
${componentMatch[2]}
|
|
376
376
|
<KeakToolbar />
|
|
377
377
|
</KeakProvider>
|
|
@@ -408,7 +408,7 @@ ${bodyContent}
|
|
|
408
408
|
const renderMatch = modified.match(/(ReactDOM\.render\s*\(\s*)([\s\S]*?)(\s*,\s*document\.getElementById)/);
|
|
409
409
|
if (renderMatch) {
|
|
410
410
|
const wrapped = `${renderMatch[1]}
|
|
411
|
-
<KeakProvider
|
|
411
|
+
<KeakProvider>
|
|
412
412
|
${renderMatch[2]}
|
|
413
413
|
<KeakToolbar />
|
|
414
414
|
</KeakProvider>
|
|
@@ -420,7 +420,7 @@ ${bodyContent}
|
|
|
420
420
|
const renderMatch = modified.match(/(root\.render\s*\(\s*)([\s\S]*?)(\s*\))/);
|
|
421
421
|
if (renderMatch) {
|
|
422
422
|
const wrapped = `${renderMatch[1]}
|
|
423
|
-
<KeakProvider
|
|
423
|
+
<KeakProvider>
|
|
424
424
|
${renderMatch[2]}
|
|
425
425
|
<KeakToolbar />
|
|
426
426
|
</KeakProvider>
|
|
@@ -513,7 +513,7 @@ Please add Keak to your app manually:
|
|
|
513
513
|
${colors.green}import { KeakProvider } from '@keak/sdk';${colors.reset}
|
|
514
514
|
|
|
515
515
|
3. Wrap your main component:
|
|
516
|
-
${colors.green}<KeakProvider
|
|
516
|
+
${colors.green}<KeakProvider><YourApp /></KeakProvider>${colors.reset}
|
|
517
517
|
|
|
518
518
|
Example for ${this.framework}:
|
|
519
519
|
${this.getFrameworkExample()}
|
|
@@ -529,7 +529,7 @@ import { KeakProvider } from '@keak/sdk';
|
|
|
529
529
|
export default function RootLayout({ children }) {
|
|
530
530
|
return (
|
|
531
531
|
<html><body>
|
|
532
|
-
<KeakProvider
|
|
532
|
+
<KeakProvider>
|
|
533
533
|
{children}
|
|
534
534
|
</KeakProvider>
|
|
535
535
|
</body></html>);
|
|
@@ -539,7 +539,7 @@ export default function RootLayout({ children }) {
|
|
|
539
539
|
import { KeakProvider } from '@keak/sdk';
|
|
540
540
|
|
|
541
541
|
root.render(
|
|
542
|
-
<KeakProvider
|
|
542
|
+
<KeakProvider>
|
|
543
543
|
<App />
|
|
544
544
|
</KeakProvider>
|
|
545
545
|
);`,
|
|
@@ -548,7 +548,7 @@ root.render(
|
|
|
548
548
|
import { KeakProvider } from '@keak/sdk';
|
|
549
549
|
|
|
550
550
|
ReactDOM.createRoot(document.getElementById('root')).render(
|
|
551
|
-
<KeakProvider
|
|
551
|
+
<KeakProvider>
|
|
552
552
|
<App />
|
|
553
553
|
</KeakProvider>
|
|
554
554
|
);`
|
|
@@ -1,170 +1,94 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Babel
|
|
3
|
-
*
|
|
2
|
+
* Keak Babel Plugin - Source Location Injector
|
|
3
|
+
* Simplified version inspired by react-source-lens
|
|
4
|
+
* Injects data-keak-file and data-keak-line attributes into JSX elements
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
|
-
console.log('[Keak Babel Plugin] MODULE LOADED - This means Babel is requiring this file');
|
|
7
|
-
|
|
8
7
|
const path = require('path');
|
|
9
8
|
|
|
10
|
-
let processedCount = 0;
|
|
11
|
-
|
|
12
9
|
function keakSourceInjectorPlugin({ types: t }) {
|
|
13
|
-
console.log('[Keak Babel Plugin] Plugin function called - Plugin loaded and initialized');
|
|
14
10
|
return {
|
|
15
11
|
name: 'keak-source-injector',
|
|
16
12
|
visitor: {
|
|
17
13
|
Program: {
|
|
18
|
-
enter(
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
enter(programPath, state) {
|
|
15
|
+
// Skip in production builds
|
|
16
|
+
if (process.env.NODE_ENV === 'production' && !state.opts.forceProduction) {
|
|
17
|
+
state.skipFile = true;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
// Skip next/font files (Babel/SWC conflict)
|
|
22
|
+
state.skipFile = false;
|
|
23
|
+
programPath.traverse({
|
|
24
24
|
ImportDeclaration(importPath) {
|
|
25
25
|
const source = importPath.node.source.value;
|
|
26
26
|
if (source.includes('next/font') || source.includes('@next/font')) {
|
|
27
27
|
state.skipFile = true;
|
|
28
|
-
importPath.stop();
|
|
28
|
+
importPath.stop();
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
});
|
|
32
|
-
},
|
|
33
|
-
exit() {
|
|
34
|
-
if (processedCount > 0) {
|
|
35
|
-
console.log(`[Keak Babel Plugin] Processed ${processedCount} JSX elements`);
|
|
36
|
-
processedCount = 0;
|
|
37
|
-
}
|
|
38
32
|
}
|
|
39
33
|
},
|
|
40
|
-
JSXOpeningElement(nodePath, state) {
|
|
41
|
-
// Skip entire file if it uses next/font (Babel/SWC conflict)
|
|
42
|
-
if (state.skipFile) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
34
|
|
|
46
|
-
|
|
47
|
-
if
|
|
35
|
+
JSXOpeningElement(nodePath, state) {
|
|
36
|
+
// Skip if file should be skipped or no location info
|
|
37
|
+
if (state.skipFile || !nodePath.node.loc) {
|
|
48
38
|
return;
|
|
49
39
|
}
|
|
50
40
|
|
|
51
|
-
// Skip if
|
|
52
|
-
const
|
|
41
|
+
// Skip if already has keak attributes
|
|
42
|
+
const hasKeakAttr = nodePath.node.attributes.some((attr) =>
|
|
53
43
|
t.isJSXAttribute(attr) &&
|
|
54
44
|
t.isJSXIdentifier(attr.name) &&
|
|
55
|
-
attr.name.name === 'data-keak-src'
|
|
45
|
+
(attr.name.name === 'data-keak-file' || attr.name.name === 'data-keak-src')
|
|
56
46
|
);
|
|
57
|
-
|
|
58
|
-
if (existingAttr) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Get source location info
|
|
63
|
-
const loc = nodePath.node.loc;
|
|
64
|
-
if (!loc) return;
|
|
47
|
+
if (hasKeakAttr) return;
|
|
65
48
|
|
|
66
49
|
const filename = state.file.opts.filename;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
if (
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
tagName = elementName.name;
|
|
90
|
-
} else if (t.isJSXMemberExpression(elementName)) {
|
|
91
|
-
// Handle cases like <motion.div>
|
|
92
|
-
tagName = elementName.property.name;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Only instrument elements we care about
|
|
96
|
-
const targetElements = new Set([
|
|
97
|
-
'div', 'span', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
|
|
98
|
-
'button', 'a', 'input', 'textarea', 'select', 'form',
|
|
99
|
-
'img', 'svg', 'canvas', 'video', 'audio',
|
|
100
|
-
'section', 'article', 'header', 'footer', 'nav', 'main',
|
|
101
|
-
'ul', 'ol', 'li', 'table', 'tr', 'td', 'th'
|
|
102
|
-
]);
|
|
103
|
-
|
|
104
|
-
// Also instrument custom components (capitalized names)
|
|
105
|
-
const isCustomComponent = tagName && tagName[0] === tagName[0].toUpperCase();
|
|
106
|
-
const isTargetElement = targetElements.has(tagName.toLowerCase());
|
|
107
|
-
|
|
108
|
-
if (!isTargetElement && !isCustomComponent) {
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Create the data attribute
|
|
113
|
-
const sourceAttr = t.jsxAttribute(
|
|
114
|
-
t.jsxIdentifier('data-keak-src'),
|
|
115
|
-
t.stringLiteral(sourceLocation)
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
// Add component context if available
|
|
119
|
-
let componentName = '';
|
|
120
|
-
let currentPath = nodePath;
|
|
121
|
-
|
|
122
|
-
// Walk up to find the containing component
|
|
123
|
-
while (currentPath) {
|
|
124
|
-
if (currentPath.isFunctionDeclaration() && currentPath.node.id) {
|
|
125
|
-
componentName = currentPath.node.id.name;
|
|
126
|
-
break;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (currentPath.isVariableDeclarator() && t.isIdentifier(currentPath.node.id)) {
|
|
130
|
-
const init = currentPath.node.init;
|
|
131
|
-
if (t.isArrowFunctionExpression(init) || t.isFunctionExpression(init)) {
|
|
132
|
-
componentName = currentPath.node.id.name;
|
|
133
|
-
break;
|
|
50
|
+
if (!filename || typeof filename !== 'string') return;
|
|
51
|
+
|
|
52
|
+
// Smart relative path detection (like react-source-lens)
|
|
53
|
+
let sourceFile;
|
|
54
|
+
|
|
55
|
+
// Try src/ directory first
|
|
56
|
+
const srcParts = filename.split('/src/');
|
|
57
|
+
if (srcParts.length > 1) {
|
|
58
|
+
sourceFile = 'src/' + srcParts[srcParts.length - 1];
|
|
59
|
+
} else {
|
|
60
|
+
// Try app/ directory (Next.js App Router)
|
|
61
|
+
const appParts = filename.split('/app/');
|
|
62
|
+
if (appParts.length > 1) {
|
|
63
|
+
sourceFile = 'app/' + appParts[appParts.length - 1];
|
|
64
|
+
} else {
|
|
65
|
+
// Try components/ directory
|
|
66
|
+
const compParts = filename.split('/components/');
|
|
67
|
+
if (compParts.length > 1) {
|
|
68
|
+
sourceFile = 'components/' + compParts[compParts.length - 1];
|
|
69
|
+
} else {
|
|
70
|
+
// Fallback: relative from cwd
|
|
71
|
+
sourceFile = path.relative(process.cwd(), filename);
|
|
134
72
|
}
|
|
135
73
|
}
|
|
136
|
-
|
|
137
|
-
currentPath = currentPath.parentPath;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Add component context attribute if found
|
|
141
|
-
if (componentName) {
|
|
142
|
-
const componentAttr = t.jsxAttribute(
|
|
143
|
-
t.jsxIdentifier('data-keak-component'),
|
|
144
|
-
t.stringLiteral(componentName)
|
|
145
|
-
);
|
|
146
|
-
nodePath.node.attributes.push(componentAttr);
|
|
147
74
|
}
|
|
148
75
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
t.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
nodePath.node.attributes.push(indexAttr);
|
|
163
|
-
}
|
|
76
|
+
const { line } = nodePath.node.loc.start;
|
|
77
|
+
|
|
78
|
+
// Add data-keak-file and data-keak-line attributes
|
|
79
|
+
nodePath.node.attributes.push(
|
|
80
|
+
t.jsxAttribute(
|
|
81
|
+
t.jsxIdentifier('data-keak-file'),
|
|
82
|
+
t.stringLiteral(sourceFile)
|
|
83
|
+
),
|
|
84
|
+
t.jsxAttribute(
|
|
85
|
+
t.jsxIdentifier('data-keak-line'),
|
|
86
|
+
t.stringLiteral(String(line))
|
|
87
|
+
)
|
|
88
|
+
);
|
|
164
89
|
}
|
|
165
90
|
}
|
|
166
91
|
};
|
|
167
92
|
}
|
|
168
93
|
|
|
169
94
|
module.exports = keakSourceInjectorPlugin;
|
|
170
|
-
|
package/src/plugins/next.cjs
CHANGED
|
@@ -1,245 +1,73 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Keak Next.js Plugin
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* for use with Keak IDE element selection.
|
|
6
|
-
*
|
|
3
|
+
* Simplified version - injects source location attributes in development only
|
|
4
|
+
*
|
|
7
5
|
* Usage in next.config.js:
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* module.exports = withKeak({
|
|
12
|
-
* // your existing Next.js config
|
|
13
|
-
* });
|
|
14
|
-
*
|
|
15
|
-
* Or for ESM (next.config.mjs):
|
|
16
|
-
*
|
|
17
|
-
* import { withKeak } from '@keak/sdk/plugins/next';
|
|
18
|
-
* export default withKeak({ ... });
|
|
6
|
+
* const { withKeak } = require('@keak/sdk/next');
|
|
7
|
+
* module.exports = withKeak({ ... });
|
|
19
8
|
*/
|
|
20
9
|
|
|
21
10
|
const path = require('path');
|
|
11
|
+
const fs = require('fs');
|
|
22
12
|
|
|
23
13
|
function withKeak(nextConfig = {}) {
|
|
24
|
-
console.log('[Keak] withKeak() called - plugin loaded successfully');
|
|
25
14
|
return {
|
|
26
15
|
...nextConfig,
|
|
27
16
|
webpack(config, options) {
|
|
28
|
-
|
|
29
|
-
const { dev, isServer } = options;
|
|
17
|
+
const { dev } = options;
|
|
30
18
|
|
|
31
|
-
// Only inject in development mode
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
19
|
+
// Only inject loader in development mode
|
|
20
|
+
if (!dev) {
|
|
21
|
+
// Call original webpack config if it exists
|
|
22
|
+
if (typeof nextConfig.webpack === 'function') {
|
|
23
|
+
return nextConfig.webpack(config, options);
|
|
24
|
+
}
|
|
25
|
+
return config;
|
|
26
|
+
}
|
|
36
27
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
paths: [process.cwd()]
|
|
43
|
-
});
|
|
44
|
-
} catch (e) {
|
|
45
|
-
// Fallback to resolving from @keak/sdk's context
|
|
46
|
-
console.warn(`[Keak] Could not resolve ${moduleName} from project, falling back to @keak/sdk`);
|
|
47
|
-
return require.resolve(moduleName);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
28
|
+
// Resolve loader path from project .keak directory or fallback
|
|
29
|
+
const projectKeakLoader = path.resolve(process.cwd(), '.keak/webpack-loader-babel/index.js');
|
|
30
|
+
const keakLoaderPath = fs.existsSync(projectKeakLoader)
|
|
31
|
+
? projectKeakLoader
|
|
32
|
+
: path.resolve(__dirname, 'webpack-loader-babel/index.js');
|
|
50
33
|
|
|
51
|
-
|
|
34
|
+
// Ensure config.module.rules exists
|
|
35
|
+
if (!config.module || !config.module.rules) {
|
|
52
36
|
config.module = config.module || {};
|
|
53
37
|
config.module.rules = config.module.rules || [];
|
|
38
|
+
}
|
|
54
39
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
// Check if loader exists in project .keak directory
|
|
71
|
-
try {
|
|
72
|
-
if (fs.existsSync(projectKeakLoader)) {
|
|
73
|
-
console.log('[Keak] Found loader in project .keak directory');
|
|
74
|
-
keakLoaderPath = projectKeakLoader;
|
|
75
|
-
loaderSource = 'project';
|
|
76
|
-
} else {
|
|
77
|
-
// Fallback to project loader path even if it doesn't exist yet
|
|
78
|
-
console.warn('[Keak] Loader not found, using fallback path:', projectKeakLoader);
|
|
79
|
-
keakLoaderPath = projectKeakLoader;
|
|
80
|
-
loaderSource = 'fallback';
|
|
81
|
-
}
|
|
82
|
-
} catch (pathError) {
|
|
83
|
-
console.error('[Keak] Error resolving loader path:', pathError.message);
|
|
84
|
-
keakLoaderPath = projectKeakLoader;
|
|
85
|
-
loaderSource = 'error';
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
console.log('[Keak] ✅ Loader path resolved:', keakLoaderPath, '(source:', loaderSource, ')');
|
|
89
|
-
console.log('[Keak] About to inspect webpack rules...');
|
|
90
|
-
console.log('[Keak] DEBUG: config exists?', !!config);
|
|
91
|
-
console.log('[Keak] DEBUG: config.module exists?', !!config.module);
|
|
92
|
-
console.log('[Keak] DEBUG: config.module.rules exists?', !!(config.module && config.module.rules));
|
|
93
|
-
console.log('[Keak] DEBUG: config.module.rules is array?', Array.isArray(config.module && config.module.rules));
|
|
94
|
-
|
|
95
|
-
// Wrap everything in try-catch to catch any errors
|
|
96
|
-
try {
|
|
97
|
-
console.log('[Keak] DEBUG: Entering try block');
|
|
98
|
-
console.log('[Keak] DEBUG: config.module exists?', !!config.module);
|
|
99
|
-
console.log('[Keak] DEBUG: config.module.rules exists?', !!(config.module && config.module.rules));
|
|
100
|
-
console.log('[Keak] Total webpack rules:', config.module && config.module.rules ? config.module.rules.length : 'undefined');
|
|
101
|
-
|
|
102
|
-
if (!config.module || !config.module.rules) {
|
|
103
|
-
console.error('[Keak] ❌ ERROR: config.module.rules is undefined!');
|
|
104
|
-
return config;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Log first few rules to understand structure
|
|
108
|
-
try {
|
|
109
|
-
console.log('[Keak] First few rules structure:');
|
|
110
|
-
config.module.rules.slice(0, 5).forEach((r, i) => {
|
|
111
|
-
console.log(`[Keak] Rule ${i}:`, {
|
|
112
|
-
hasOneOf: Array.isArray(r.oneOf),
|
|
113
|
-
oneOfLength: Array.isArray(r.oneOf) ? r.oneOf.length : 'N/A',
|
|
114
|
-
test: r.test ? r.test.toString().substring(0, 50) : 'no test',
|
|
115
|
-
hasUse: !!r.use,
|
|
116
|
-
useType: r.use ? (Array.isArray(r.use) ? 'array' : typeof r.use) : 'none'
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
} catch (e) {
|
|
120
|
-
console.log('[Keak] Error logging rules:', e.message);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Based on Next.js webpack structure: Find the oneOf array and add our loader
|
|
124
|
-
// Next.js uses oneOf arrays to process files - we need to add our loader there
|
|
125
|
-
let loaderAdded = false;
|
|
126
|
-
|
|
127
|
-
console.log('[Keak] Attempting Strategy 1: Finding oneOf rule...');
|
|
128
|
-
// Strategy 1: Find the oneOf rule (recommended approach from web search)
|
|
129
|
-
const oneOfRule = config.module.rules.find((rule) => Array.isArray(rule.oneOf));
|
|
130
|
-
console.log('[Keak] Strategy 1 result:', oneOfRule ? 'Found oneOf rule' : 'No oneOf rule found');
|
|
131
|
-
|
|
132
|
-
if (oneOfRule && oneOfRule.oneOf) {
|
|
133
|
-
console.log(`[Keak] ✅ Found oneOf array with ${oneOfRule.oneOf.length} entries`);
|
|
134
|
-
|
|
135
|
-
// Add our loader to the BEGINNING of oneOf array so it runs BEFORE SWC
|
|
136
|
-
// This transforms raw JSX to inject attributes before compilation
|
|
137
|
-
const preRule = {
|
|
138
|
-
test: /\.[jt]sx?$/,
|
|
139
|
-
exclude: [
|
|
140
|
-
/node_modules/,
|
|
141
|
-
/\.next\//,
|
|
142
|
-
/webpack/,
|
|
143
|
-
/next\/dist/
|
|
144
|
-
// NOTE: Removed /\.server\.[jt]sx?$/ exclusion to process server components
|
|
145
|
-
],
|
|
146
|
-
enforce: 'pre', // Run BEFORE SWC (pre-compilation)
|
|
147
|
-
use: [
|
|
148
|
-
{
|
|
149
|
-
loader: keakLoaderPath,
|
|
150
|
-
options: {
|
|
151
|
-
projectRoot: process.cwd(),
|
|
152
|
-
includeElementIndex: true,
|
|
153
|
-
devWarnings: dev,
|
|
154
|
-
skipPatterns: [
|
|
155
|
-
// NOTE: Removed /(\.server\.[jt]sx?$)/ to process server components
|
|
156
|
-
/webpack/,
|
|
157
|
-
/\.next\//,
|
|
158
|
-
/next\/dist/
|
|
159
|
-
]
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
]
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
// Add to the BEGINNING of oneOf array (runs before SWC processes files)
|
|
166
|
-
oneOfRule.oneOf.unshift(preRule);
|
|
167
|
-
|
|
168
|
-
console.log(`[Keak] ✅ Added pre-compilation loader to oneOf array (now ${oneOfRule.oneOf.length} entries, runs before SWC)`);
|
|
169
|
-
loaderAdded = true;
|
|
170
|
-
} else {
|
|
171
|
-
console.log('[Keak] No oneOf array found, trying alternative approaches...');
|
|
172
|
-
|
|
173
|
-
// Strategy 2: Look for rules with oneOf property (nested)
|
|
174
|
-
for (let i = 0; i < config.module.rules.length; i++) {
|
|
175
|
-
const rule = config.module.rules[i];
|
|
176
|
-
if (rule.oneOf && Array.isArray(rule.oneOf)) {
|
|
177
|
-
console.log(`[Keak] Found oneOf in rule ${i} with ${rule.oneOf.length} entries`);
|
|
178
|
-
|
|
179
|
-
// Add pre-compilation loader to the BEGINNING of this oneOf array
|
|
180
|
-
rule.oneOf.unshift({
|
|
181
|
-
test: /\.[jt]sx?$/,
|
|
182
|
-
exclude: [/node_modules/, /\.next\//, /webpack/, /next\/dist/],
|
|
183
|
-
enforce: 'pre', // Run BEFORE SWC
|
|
184
|
-
use: [
|
|
185
|
-
{
|
|
186
|
-
loader: keakLoaderPath,
|
|
187
|
-
options: {
|
|
188
|
-
projectRoot: process.cwd(),
|
|
189
|
-
includeElementIndex: true,
|
|
190
|
-
devWarnings: dev,
|
|
191
|
-
skipPatterns: [] // Process all files including server components
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
]
|
|
195
|
-
});
|
|
196
|
-
console.log(`[Keak] ✅ Added pre-compilation loader to oneOf array (now ${rule.oneOf.length} entries)`);
|
|
197
|
-
loaderAdded = true;
|
|
198
|
-
break;
|
|
199
|
-
}
|
|
40
|
+
// Create the loader rule
|
|
41
|
+
const keakRule = {
|
|
42
|
+
test: /\.[jt]sx?$/,
|
|
43
|
+
exclude: [
|
|
44
|
+
/node_modules/,
|
|
45
|
+
/\.next\//,
|
|
46
|
+
/webpack/,
|
|
47
|
+
/next\/dist/
|
|
48
|
+
],
|
|
49
|
+
enforce: 'pre', // Run BEFORE SWC compilation
|
|
50
|
+
use: [
|
|
51
|
+
{
|
|
52
|
+
loader: keakLoaderPath,
|
|
53
|
+
options: {
|
|
54
|
+
projectRoot: process.cwd()
|
|
200
55
|
}
|
|
201
56
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
enforce: 'pre', // Run BEFORE SWC
|
|
211
|
-
use: [
|
|
212
|
-
{
|
|
213
|
-
loader: keakLoaderPath,
|
|
214
|
-
options: {
|
|
215
|
-
projectRoot: process.cwd(),
|
|
216
|
-
includeElementIndex: true,
|
|
217
|
-
devWarnings: dev,
|
|
218
|
-
skipPatterns: [] // Process all files including server components
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
]
|
|
222
|
-
});
|
|
223
|
-
console.log('[Keak] ✅ Added pre-compilation loader rule with enforce:pre (fallback)');
|
|
224
|
-
loaderAdded = true;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (!loaderAdded) {
|
|
228
|
-
console.error('[Keak] ❌ ERROR: Failed to add loader using any strategy!');
|
|
229
|
-
} else {
|
|
230
|
-
console.log('[Keak] ✅ Loader successfully added to webpack config');
|
|
231
|
-
}
|
|
232
|
-
} catch (error) {
|
|
233
|
-
console.error('[Keak] ❌ ERROR in loader injection block:', error);
|
|
234
|
-
console.error('[Keak] Error message:', error.message);
|
|
235
|
-
console.error('[Keak] Error stack:', error.stack);
|
|
236
|
-
// Don't throw - let webpack continue even if loader injection fails
|
|
237
|
-
}
|
|
57
|
+
]
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Try to inject into oneOf array (Next.js standard structure)
|
|
61
|
+
const oneOfRule = config.module.rules.find((rule) => Array.isArray(rule.oneOf));
|
|
62
|
+
if (oneOfRule && oneOfRule.oneOf) {
|
|
63
|
+
// Add to beginning so it runs before SWC
|
|
64
|
+
oneOfRule.oneOf.unshift(keakRule);
|
|
238
65
|
} else {
|
|
239
|
-
|
|
66
|
+
// Fallback: Add as top-level rule with enforce: 'pre'
|
|
67
|
+
config.module.rules.unshift(keakRule);
|
|
240
68
|
}
|
|
241
69
|
|
|
242
|
-
// Call
|
|
70
|
+
// Call original webpack config if it exists
|
|
243
71
|
if (typeof nextConfig.webpack === 'function') {
|
|
244
72
|
return nextConfig.webpack(config, options);
|
|
245
73
|
}
|
|
@@ -250,4 +78,3 @@ function withKeak(nextConfig = {}) {
|
|
|
250
78
|
}
|
|
251
79
|
|
|
252
80
|
module.exports = { withKeak };
|
|
253
|
-
|