juejin-book-vite
juejin-book-vite copied to clipboard
24小节关于windows用户可能会报的错误处理
环境
OS:Windows 11 22H2 Node:16.14.2 browser: Google Chrome 101.0.4951.67
依赖预构建
首先是依赖预构建部分
路径中的分割符经过esbuild后会被吞掉,对着esbuild打断点看了半天也不知道为什么。
后尝试在wsl中运行,发现没有问题,确定是windows路径问题后,去看了一下vite的实现发现vite用的是相对路径
尝试修改为相对路径
// src\node\optimizer\preBundlePlugin.ts
build.onLoad(
{
filter: /.*/,
namespace: "dep",
},
async (loadInfo) => {
await init;
const id = loadInfo.path;
const root = process.cwd();
const entryPath = resolve.sync(id, { basedir: root });
const code = await fs.readFile(entryPath, "utf-8");
const [imports, exports] = await parse(code);
let proxyModule = [];
+ let relativePath = normalizePath(path.relative(root, entryPath))
+ if (
+ !relativePath.startsWith('./') &&
+ !relativePath.startsWith('../') &&
+ relativePath !== '.'
+ ) {
+ relativePath = `./${relativePath}`
+ }
// cjs
if (!imports.length && !exports.length) {
const res = require(entryPath);
const specifiers = Object.keys(res);
proxyModule.push(
+ `export { ${specifiers.join(",")} } from "${relativePath}"`,
+ `export default require("${relativePath}")`
- `export { ${specifiers.join(",")} } from "${entryPath}"`,
- `export default require("${entryPath}")`
);
} else {
if (exports.includes("default")) {
+ proxyModule.push(`import d from "${relativePath}";export default d`);
- proxyModule.push(`import d from "${entryPath}";export default d`);
}
+ proxyModule.push(`export * from "${relativePath}"`);
- proxyModule.push(`export * from "${entryPath}"`);
}
debug("代理模块内容: %o", proxyModule.join("\n"));
const loader = path.extname(entryPath).slice(1);
return {
loader: loader as Loader,
contents: proxyModule.join("\n"),
resolveDir: root,
};
}
);
// src\node\utils.ts
export function slash(p: string): string {
return p.replace(/\\/g, '/')
}
export const isWindows = os.platform() === 'win32'
export function normalizePath(id: string): string {
return path.posix.normalize(isWindows ? slash(id) : id)
}
改完这些就可以进行依赖预构建了
ps:vite中没有加上export { ${specifiers.join(",")} } from "${entryPath}"
这是为什么?
JS/TS/JSX/TSX 编译能力
还是一样的问题,绝对路径中的分割符丢失
vite中对bare import 处理成绝对路径 /node_modules/xxx
// src/node/plugins/importAnalysis.ts
if (BARE_IMPORT_RE.test(modSource)) {
- const bundlePath = path.join(
- serverContext.root,
- PRE_BUNDLE_DIR,
- `${modSource}.js`
- )
+ const bundlePath = normalizePath(
+ path.join('/', PRE_BUNDLE_DIR, `${modSource}.js`)
+ )
ms.overwrite(modStart, modEnd, bundlePath)
}
此时react已能正确加载
接着处理./App.tsx
// src\node\plugins\resolve.ts
if (id.startsWith('.')) {
if (!importer) {
throw new Error('`importer` should not be undefined')
}
const hasExtension = path.extname(id).length > 1
let resolvedId: string
// 2.1 包含文件名后缀
// 如 ./App.tsx
if (hasExtension) {
resolvedId = resolve.sync(id, { basedir: path.dirname(importer) })
if (await pathExists(resolvedId)) {
+ return { id }
- return { id: resolvedId }
}
}
// 2.2 不包含文件名后缀
// 如 ./App
else {
// ./App -> ./App.tsx
for (const extname of DEFAULT_EXTENSIONS) {
try {
const withExtension = `${id}${extname}`
resolvedId = resolve.sync(withExtension, {
basedir: path.dirname(importer),
})
if (await pathExists(resolvedId)) {
+ return { id: withExtension }
- return { id: resolvedId }
}
} catch (e) {
continue
}
}
}
}
修改完后已经能够正确加载(本小节没处理静态资源,需要注释掉css、svg的资源)
类型报错
- src\node\server\middlewares\transform.ts
// error 不能将类型“string”分配给类型“SourceDescription”。
if (result && typeof result !== 'string') {
result = result.code
}
修改
// src\node\pluginContainer.ts
export interface PluginContainer {
resolveId(id: string, importer?: string): Promise<PartialResolvedId | null>
load(id: string): Promise<LoadResult | null>
- transform(code: string, id: string): Promise<SourceDescription | null>
+ transform(code: string, id: string): Promise<LoadResult | null>
}
- src\node\plugins\importAnalysis.ts
// error 属性“resolve”在类型“Plugin”上不存在。
const resolved = await this.resolve(modSource, id)
// src\node\plugins\importAnalysis.ts
+ import type { PluginContext } from 'rollup'
// ...
// transform函数签名增加this类型
- async transform(code: string, id: string)
+ async transform(this: PluginContext, code: string, id: string)
最后的 async transform(this: PluginContext, code: string, id: string) 不能这么写吧?相当于给transform方法加了个参数this