@keak/sdk 2.0.2 → 2.0.3
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keak/sdk",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
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/",
|
package/src/plugins/next.cjs
CHANGED
|
@@ -14,10 +14,13 @@ function withKeak(nextConfig = {}) {
|
|
|
14
14
|
return {
|
|
15
15
|
...nextConfig,
|
|
16
16
|
webpack(config, options) {
|
|
17
|
-
const { dev } = options;
|
|
17
|
+
const { dev, isServer } = options;
|
|
18
|
+
|
|
19
|
+
console.log('[Keak Plugin] webpack called - dev:', dev, 'isServer:', isServer);
|
|
18
20
|
|
|
19
21
|
// Only inject loader in development mode
|
|
20
22
|
if (!dev) {
|
|
23
|
+
console.log('[Keak Plugin] Skipping - not in development mode');
|
|
21
24
|
// Call original webpack config if it exists
|
|
22
25
|
if (typeof nextConfig.webpack === 'function') {
|
|
23
26
|
return nextConfig.webpack(config, options);
|
|
@@ -30,6 +33,9 @@ function withKeak(nextConfig = {}) {
|
|
|
30
33
|
const keakLoaderPath = fs.existsSync(projectKeakLoader)
|
|
31
34
|
? projectKeakLoader
|
|
32
35
|
: path.resolve(__dirname, 'webpack-loader-babel/index.js');
|
|
36
|
+
|
|
37
|
+
console.log('[Keak Plugin] Using loader path:', keakLoaderPath);
|
|
38
|
+
console.log('[Keak Plugin] Loader exists:', fs.existsSync(keakLoaderPath));
|
|
33
39
|
|
|
34
40
|
// Ensure config.module.rules exists
|
|
35
41
|
if (!config.module || !config.module.rules) {
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Webpack loader that
|
|
3
|
-
*
|
|
2
|
+
* Webpack loader that injects Keak source attributes into JSX
|
|
3
|
+
*
|
|
4
|
+
* Uses regex-based injection instead of full Babel AST transformation
|
|
5
|
+
* to avoid interfering with React's module resolution in Next.js 15
|
|
6
|
+
*
|
|
4
7
|
* Only runs in development mode
|
|
5
8
|
*/
|
|
6
9
|
|
|
7
10
|
const path = require('path');
|
|
8
|
-
const babelParser = require('@babel/parser');
|
|
9
|
-
const babelTraverse = require('@babel/traverse').default;
|
|
10
|
-
const babelGenerator = require('@babel/generator').default;
|
|
11
|
-
const t = require('@babel/types');
|
|
12
11
|
|
|
13
|
-
module.exports = function
|
|
12
|
+
module.exports = function keakSourceLoader(source) {
|
|
14
13
|
this.cacheable(true);
|
|
15
14
|
|
|
16
15
|
const resourcePath = this.resourcePath;
|
|
@@ -22,101 +21,87 @@ module.exports = function keakLoaderBabel(source) {
|
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
// Skip if not a JSX/TSX file
|
|
25
|
-
if (!/\.(jsx|tsx
|
|
24
|
+
if (!/\.(jsx|tsx)$/.test(resourcePath)) {
|
|
26
25
|
return source;
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
'objectRestSpread',
|
|
39
|
-
'dynamicImport',
|
|
40
|
-
'nullishCoalescingOperator',
|
|
41
|
-
'optionalChaining'
|
|
42
|
-
]
|
|
43
|
-
});
|
|
28
|
+
// Skip node_modules
|
|
29
|
+
if (resourcePath.includes('node_modules')) {
|
|
30
|
+
return source;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Skip files that use next/font (known to conflict with Babel processing)
|
|
34
|
+
if (source.includes('next/font') || source.includes('@next/font')) {
|
|
35
|
+
return source;
|
|
36
|
+
}
|
|
44
37
|
|
|
45
|
-
|
|
38
|
+
// Skip if already processed
|
|
39
|
+
if (source.includes('data-keak-src=')) {
|
|
40
|
+
return source;
|
|
41
|
+
}
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
43
|
+
try {
|
|
44
|
+
// Smart relative path detection
|
|
45
|
+
let sourceFile;
|
|
46
|
+
const srcParts = resourcePath.split('/src/');
|
|
47
|
+
if (srcParts.length > 1) {
|
|
48
|
+
sourceFile = 'src/' + srcParts[srcParts.length - 1];
|
|
49
|
+
} else {
|
|
50
|
+
const appParts = resourcePath.split('/app/');
|
|
51
|
+
if (appParts.length > 1) {
|
|
52
|
+
sourceFile = 'app/' + appParts[appParts.length - 1];
|
|
53
|
+
} else {
|
|
54
|
+
const compParts = resourcePath.split('/components/');
|
|
55
|
+
if (compParts.length > 1) {
|
|
56
|
+
sourceFile = 'components/' + compParts[compParts.length - 1];
|
|
57
|
+
} else {
|
|
58
|
+
sourceFile = path.relative(process.cwd(), resourcePath);
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
if (skipFile) {
|
|
59
|
-
return source;
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
63
|
+
// Track the current line number
|
|
64
|
+
const lines = source.split('\n');
|
|
65
|
+
const processedLines = [];
|
|
66
|
+
|
|
67
|
+
for (let i = 0; i < lines.length; i++) {
|
|
68
|
+
const line = lines[i];
|
|
69
|
+
const lineNumber = i + 1;
|
|
70
|
+
|
|
71
|
+
// Match JSX opening tags: <ComponentName or <div, etc.
|
|
72
|
+
// But not self-closing tags that are already complete, or fragments
|
|
73
|
+
const processedLine = line.replace(
|
|
74
|
+
// Match: <TagName followed by space, newline, or >
|
|
75
|
+
// But NOT: </tag, <>, <Fragment
|
|
76
|
+
/<([A-Z][a-zA-Z0-9]*|[a-z][a-zA-Z0-9-]*)(\s|>)/g,
|
|
77
|
+
(match, tagName, after) => {
|
|
78
|
+
// Skip fragments and closing tags
|
|
79
|
+
if (tagName === 'Fragment' || tagName === '') {
|
|
80
|
+
return match;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Skip if this looks like it already has data-keak attributes
|
|
84
|
+
if (line.includes('data-keak-')) {
|
|
85
|
+
return match;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Inject the attribute
|
|
89
|
+
const attr = ` data-keak-src="${sourceFile}:${lineNumber}:1"`;
|
|
90
|
+
|
|
91
|
+
if (after === '>') {
|
|
92
|
+
// <tag> -> <tag data-keak-src="...">
|
|
93
|
+
return `<${tagName}${attr}>`;
|
|
87
94
|
} else {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
sourceFile = 'components/' + compParts[compParts.length - 1];
|
|
91
|
-
} else {
|
|
92
|
-
sourceFile = path.relative(process.cwd(), resourcePath);
|
|
93
|
-
}
|
|
95
|
+
// <tag -> <tag data-keak-src="..."
|
|
96
|
+
return `<${tagName}${attr}${after}`;
|
|
94
97
|
}
|
|
95
98
|
}
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
processedLines.push(processedLine);
|
|
102
|
+
}
|
|
96
103
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// Add data-keak-file and data-keak-line attributes
|
|
100
|
-
node.attributes.push(
|
|
101
|
-
t.jsxAttribute(
|
|
102
|
-
t.jsxIdentifier('data-keak-file'),
|
|
103
|
-
t.stringLiteral(sourceFile)
|
|
104
|
-
),
|
|
105
|
-
t.jsxAttribute(
|
|
106
|
-
t.jsxIdentifier('data-keak-line'),
|
|
107
|
-
t.stringLiteral(String(line))
|
|
108
|
-
)
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// Generate transformed code
|
|
114
|
-
const output = babelGenerator(ast, {
|
|
115
|
-
retainLines: false,
|
|
116
|
-
compact: false
|
|
117
|
-
}, source);
|
|
118
|
-
|
|
119
|
-
return output.code;
|
|
104
|
+
return processedLines.join('\n');
|
|
120
105
|
} catch (error) {
|
|
121
106
|
// Return original source on error
|
|
122
107
|
console.error(`[keak-loader] Error processing ${resourcePath}:`, error.message);
|