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?
The issue lies in the fact that NodeJS and the Browser both have a module called crypto
that implements the webcrypto standard. Those modules are compatible, but need to be accessed differently. In NodeJS it can be used directly but 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, so 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 familiar 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With