juejin-book-vite icon indicating copy to clipboard operation
juejin-book-vite copied to clipboard

24小节关于windows用户可能会报的错误处理

Open ln0y opened this issue 2 years ago • 1 comments

环境

OS:Windows 11 22H2 Node:16.14.2 browser: Google Chrome 101.0.4951.67

依赖预构建

首先是依赖预构建部分

image

路径中的分割符经过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 编译能力

还是一样的问题,绝对路径中的分割符丢失

image

image

vite中对bare import 处理成绝对路径 /node_modules/xxx

image

// 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已能正确加载

image

接着处理./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的资源)

image

类型报错

  1. 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>
}
  1. 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) 

ln0y avatar May 23 '22 15:05 ln0y

最后的 async transform(this: PluginContext, code: string, id: string) 不能这么写吧?相当于给transform方法加了个参数this

admin00001 avatar Nov 27 '22 05:11 admin00001