mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-29 04:00:36 +00:00
- Remove duplicate webui build in vscode-ide-companion (fixes double build) - Fix misleading [watch] log messages in esbuild.js (only show in watch mode) - Update vite-plugin-dts to ^4.5.4 for TypeScript 5.8+ support - Update baseline-browser-mapping to ^2.9.19 to silence outdated data warnings - Fix vitest config to use @qwen-code/qwen-code-core instead of old gemini-cli-core - Add resolve.alias in cli vitest.config.ts for source-based testing - Add npm run dev script for running from TypeScript source without build Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
197 lines
5.4 KiB
JavaScript
197 lines
5.4 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2025 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import esbuild from 'esbuild';
|
|
import { createRequire } from 'node:module';
|
|
import { dirname, resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const production = process.argv.includes('--production');
|
|
const watch = process.argv.includes('--watch');
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const repoRoot = resolve(__dirname, '..', '..');
|
|
const rootRequire = createRequire(resolve(repoRoot, 'package.json'));
|
|
|
|
/**
|
|
* @type {import('esbuild').Plugin}
|
|
*/
|
|
const esbuildProblemMatcherPlugin = {
|
|
name: 'esbuild-problem-matcher',
|
|
|
|
setup(build) {
|
|
const isWatchMode = build.initialOptions.watch;
|
|
build.onStart(() => {
|
|
if (isWatchMode) {
|
|
console.log('[watch] build started');
|
|
}
|
|
});
|
|
build.onEnd((result) => {
|
|
result.errors.forEach(({ text, location }) => {
|
|
console.error(`✘ [ERROR] ${text}`);
|
|
console.error(
|
|
` ${location.file}:${location.line}:${location.column}:`,
|
|
);
|
|
});
|
|
if (isWatchMode) {
|
|
console.log('[watch] build finished');
|
|
}
|
|
});
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Ensure a single React copy in the webview bundle by resolving from repo root.
|
|
* Prevents mixing React 18/19 element types when nested node_modules exist.
|
|
* @type {import('esbuild').Plugin}
|
|
*/
|
|
const resolveFromRoot = (moduleId) => {
|
|
try {
|
|
return rootRequire.resolve(moduleId);
|
|
} catch {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
const reactDedupPlugin = {
|
|
name: 'react-dedup',
|
|
setup(build) {
|
|
const aliases = [
|
|
'react',
|
|
'react-dom',
|
|
'react-dom/client',
|
|
'react/jsx-runtime',
|
|
'react/jsx-dev-runtime',
|
|
];
|
|
|
|
for (const alias of aliases) {
|
|
build.onResolve({ filter: new RegExp(`^${alias}$`) }, () => {
|
|
const resolved = resolveFromRoot(alias);
|
|
if (!resolved) {
|
|
return undefined;
|
|
}
|
|
return { path: resolved };
|
|
});
|
|
}
|
|
},
|
|
};
|
|
|
|
/**
|
|
* @type {import('esbuild').Plugin}
|
|
*/
|
|
const cssInjectPlugin = {
|
|
name: 'css-inject',
|
|
setup(build) {
|
|
// Handle CSS files
|
|
build.onLoad({ filter: /\.css$/ }, async (args) => {
|
|
const fs = await import('fs');
|
|
const postcss = (await import('postcss')).default;
|
|
const tailwindcss = (await import('tailwindcss')).default;
|
|
const autoprefixer = (await import('autoprefixer')).default;
|
|
|
|
let css = await fs.promises.readFile(args.path, 'utf8');
|
|
|
|
// For styles.css, we need to resolve @import statements
|
|
if (args.path.endsWith('styles.css')) {
|
|
// Read all imported CSS files and inline them
|
|
const importRegex = /@import\s+'([^']+)';/g;
|
|
let match;
|
|
const basePath = args.path.substring(0, args.path.lastIndexOf('/'));
|
|
while ((match = importRegex.exec(css)) !== null) {
|
|
const importPath = match[1];
|
|
// Resolve relative paths correctly
|
|
let fullPath;
|
|
if (importPath.startsWith('./')) {
|
|
fullPath = basePath + importPath.substring(1);
|
|
} else if (importPath.startsWith('../')) {
|
|
fullPath = basePath + '/' + importPath;
|
|
} else {
|
|
fullPath = basePath + '/' + importPath;
|
|
}
|
|
|
|
try {
|
|
const importedCss = await fs.promises.readFile(fullPath, 'utf8');
|
|
css = css.replace(match[0], importedCss);
|
|
} catch (err) {
|
|
console.warn(`Could not import ${fullPath}: ${err.message}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process with PostCSS (Tailwind + Autoprefixer)
|
|
const result = await postcss([tailwindcss, autoprefixer]).process(css, {
|
|
from: args.path,
|
|
to: args.path,
|
|
});
|
|
|
|
return {
|
|
contents: `
|
|
const style = document.createElement('style');
|
|
style.textContent = ${JSON.stringify(result.css)};
|
|
document.head.appendChild(style);
|
|
`,
|
|
loader: 'js',
|
|
};
|
|
});
|
|
},
|
|
};
|
|
|
|
async function main() {
|
|
// Build extension
|
|
const extensionCtx = await esbuild.context({
|
|
entryPoints: ['src/extension.ts'],
|
|
bundle: true,
|
|
format: 'cjs',
|
|
minify: production,
|
|
sourcemap: !production,
|
|
sourcesContent: false,
|
|
platform: 'node',
|
|
outfile: 'dist/extension.cjs',
|
|
external: ['vscode'],
|
|
logLevel: 'silent',
|
|
banner: {
|
|
js: `const import_meta = { url: require('url').pathToFileURL(__filename).href };`,
|
|
},
|
|
define: {
|
|
'import.meta.url': 'import_meta.url',
|
|
},
|
|
plugins: [
|
|
/* add to the end of plugins array */
|
|
esbuildProblemMatcherPlugin,
|
|
],
|
|
loader: { '.node': 'file' },
|
|
});
|
|
|
|
// Build webview
|
|
const webviewCtx = await esbuild.context({
|
|
entryPoints: ['src/webview/index.tsx'],
|
|
bundle: true,
|
|
format: 'iife',
|
|
minify: production,
|
|
sourcemap: !production,
|
|
sourcesContent: false,
|
|
platform: 'browser',
|
|
outfile: 'dist/webview.js',
|
|
logLevel: 'silent',
|
|
plugins: [reactDedupPlugin, cssInjectPlugin, esbuildProblemMatcherPlugin],
|
|
jsx: 'automatic', // Use new JSX transform (React 17+)
|
|
define: {
|
|
'process.env.NODE_ENV': production ? '"production"' : '"development"',
|
|
},
|
|
});
|
|
|
|
if (watch) {
|
|
await Promise.all([extensionCtx.watch(), webviewCtx.watch()]);
|
|
} else {
|
|
await Promise.all([extensionCtx.rebuild(), webviewCtx.rebuild()]);
|
|
await Promise.all([extensionCtx.dispose(), webviewCtx.dispose()]);
|
|
}
|
|
}
|
|
|
|
main().catch((e) => {
|
|
console.error(e);
|
|
process.exit(1);
|
|
});
|