Vue3/Vite: 模块已被外部化

huangapple go评论63阅读模式
英文:

Vue3/Vite: module has been externalized

问题

你的代码中出现了关于使用 crypto 模块的问题。在浏览器环境中,crypto 模块通常会被 externalize,导致无法直接访问 crypto.subtle。这可能是由于 Vite 默认设置中进行了配置,但在你的 vite.config.js 中没有看到明确的设置。

要解决这个问题,你可以尝试在你的项目中添加以下配置到 vite.config.js 中:

// vite.config.js

export default defineConfig({
  // ...其他配置
  
  build: {
    rollupOptions: {
      // 防止 crypto 模块 externalize
      external: ['crypto'],
    },
  },
})

这个配置会告诉 Vite 在构建时不要 externalize crypto 模块,从而使你可以在客户端代码中访问 crypto.subtle

请确保添加这个配置后重新构建你的应用程序以查看是否问题已解决。

英文:

I'm trying to use crypto to hash strings in a Vue 3 app.

async function hash (token) {
    const data = new TextEncoder().encode(token)
    const byteHash = await crypto.subtle.digest("SHA-256", data)
    //                            ^ the below error is thrown here

    const arrayHash = Array.from(new Uint8Array(byteHash))
    const hexHash = arrayHash.map(b => b.toString(16).padStart(2, '0')).join('').toLocaleUpperCase()

    return hexHash
}

From my understanding, crypto is available in the browser nowadays, so it needs no browserify replacement.

Nevertheless, I'm getting the following error in my browser console:

Error: Module "crypto" has been externalized for browser compatibility. Cannot access "crypto.subtle" in client code.

I interpret this as "Vite is configured to externalize the crypto module in the build process". But I can see no such setting in my vite.config.js:

// Plugins:
import vue from '@vitejs/plugin-vue'
import vuetify from 'vite-plugin-vuetify'

// Utilies:
import { defineConfig } from 'vite'
import { fileURLToPath, URL } from 'node:url'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    // https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vite-plugin
    vuetify({
      autoImport: true
    })
  ],
  define: { 'process.env': {} },
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    },
    extensions: ['.js', '.json', '.jsx', '.mjs', '.ts', '.tsx', '.vue']
  },
  server: {
    port: 3000
  },
  test: {
    setupFiles: ['../vuetify.config.js'],
    deps: {
      inline: ['vuetify']
    },
    globals: true
  }
})

Are there any "baked in" Vite default settings, that could cause this? Is this configured somewere else? How can I fix this issue and use the crypto module in my app?

答案1

得分: 1

问题在于NodeJS和浏览器都有一个名为crypto的模块(实现了webcrypto标准),它们是兼容的,但需要以不同的方式访问,因为在浏览器中,它是由不存在于NodeJS的window上下文提供的。

如果您直接在浏览器中工作,您就看不到这个区别,因为window是默认上下文。

但是Vite在NodeJS上下文中工作,它(正确地)认为在浏览器中没有作为crypto的模块,因此会引发错误。它不知道/不关心这个模块在浏览器中也以window.crypto存在。

也许可以在vite.config.js中进行某种配置,但我对它不太熟悉。

相反,我提出了以下解决方案,它在两种环境中都有效:

function getCrypto() {
  try {
    return window.crypto;
  } catch {
    return crypto;
  }
}
async function hash(token) {
  const compatibleCrypto = getCrypto();

  const data = new TextEncoder().encode(token);
  const byteHash = await compatibleCrypto.subtle.digest('SHA-256', data);

  const arrayHash = Array.from(new Uint8Array(byteHash));
  const hexHash = arrayHash
    .map(b => b.toString(16).padStart(2, '0'))
    .join('')
    .toLocaleUpperCase();

  return hexHash;
}

这个函数现在在两种环境中都可以工作。

英文:

The issue lies in the fact that NodeJS and the Browser both have a module called crypto (that implements the webcrypto standard) that are compatible, but need to be accessed differently, because in the browser it is provided by the window context that does not exist in NodeJS.

You don't see the difference if you are working directly in the browser, as window is the default context.

But Vite is working in the NodeJS context, it (correctly) decides that this module is not available as crypto in the browser and thus throws the error. It does not know/care that this module exists in the browser as well but as window.crypto.

Maybe this can be configured in vite.config.js somehow, but I am not very firm with it.

I came up with the following solution instead, which works in both environments:

function getCrypto() {
  try {
    return window.crypto;
  } catch {
    return crypto;
  }
}
async function hash(token) {
  const compatibleCrypto = getCrypto();

  const data = new TextEncoder().encode(token);
  const byteHash = await compatibleCrypto.subtle.digest('SHA-256', data);

  const arrayHash = Array.from(new Uint8Array(byteHash));
  const hexHash = arrayHash
    .map(b => b.toString(16).padStart(2, '0'))
    .join('')
    .toLocaleUpperCase();

  return hexHash;
}

This function works in both environments now.

huangapple
  • 本文由 发表于 2023年5月6日 18:35:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76188415.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定