Vue3/Vite: Externalizing modules
P粉107991030
P粉107991030 2023-08-26 13:45:43
0
1
761
<p>I'm trying to hash a string using <code>crypto</code> in a Vue 3 application. </p> <pre class="brush:js;toolbar:false;">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 } </pre> <p>As far as I know, <code>crypto</code> is now available in browsers, so there is no need to use <code>browserify</code> instead. </p> <p>However, I encountered the following error in the browser console: </p> <pre class="brush:js;toolbar:false;">Error: Module "crypto" has been externalized for browser compatibility. Cannot access "crypto.subtle" in client code. </pre> <p>I understand this error as "Vite is configured to externalize the <code>crypto</code> module during the build process." But I don't find such a setting in my <code>vite.config.js</code>:</p> <pre class="brush:js;toolbar:false;">// Plugins: import vue from '@vitejs/plugin-vue' import vuetify from 'vite-plugin-vuetify' // Utilities: 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 } }) </pre> <p>Are there any "built-in" Vite default settings that could cause this issue? Is this issue configured elsewhere? How can I solve this problem and use the <code>crypto</code> module in my application? </p>
P粉107991030
P粉107991030

reply all(1)
P粉019353247

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

If you work directly in the browser, you won't see the difference because window is the default context.

But Vite is working in the context of NodeJS, it (correctly) believes that this module is not available as crypto in the browser, and therefore throws an error. It doesn't know/care that this module also exists in the browser, but as window.crypto.

Maybe it can be configured in vite.config.js, but I'm not very familiar with it.

I came up with the following solution, 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;
}

Now this function works in both environments.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template