Typescript+webpack下Node与浏览器双端环境变量的适配判断问题
问题根因
核心问题是var的变量提升特性导致全局localStorage被局部变量遮挡:
- 你在if代码块内用
var localStorage声明的变量,不存在块级作用域限制,会被提升到当前模块作用域的最顶部,初始值为undefined - 你执行
typeof localStorage判断时,读取的是当前作用域下这个已经被声明但未赋值的局部变量,自然返回undefined,触发了Node分支逻辑 - 你删除if块后能正常使用
localStorage,是因为模块内没有了同名局部变量,访问的是全局window上的原生localStorage属性,和你手动打印能拿到对象的表现一致。
解决方案
方案1:调整判断逻辑,避免变量遮挡(最通用,无需修改打包配置)
直接从全局对象读取localStorage做判断,不要在模块作用域内声明和全局同名的localStorage变量,避免变量提升问题:
// 兼容多环境的全局对象读取 const getGlobal = () => { if (typeof globalThis !== 'undefined') return globalThis if (typeof window !== 'undefined') return window if (typeof global !== 'undefined') return global throw new Error('unable to locate global object') } const globalObj = getGlobal() if (typeof globalObj.localStorage === "undefined" || globalObj.localStorage === null) { console.log("need to use Node localStorage") const { LocalStorage } = require('node-localstorage') // 将实例挂载到全局,后续所有地方直接读globalThis.localStorage即可 globalObj.localStorage = new LocalStorage('./localStorage') } else { console.log("using Browser localStorage") }
如果需要更简洁的写法,可以直接用空值合并运算符:
const globalObj = typeof globalThis !== 'undefined' ? globalThis : (typeof window !== 'undefined' ? window : global) globalObj.localStorage = globalObj.localStorage ?? new (require('node-localstorage').LocalStorage)('./localStorage')
方案2:配合打包工具做环境区分(更可靠,无冗余代码)
如果你的包会分别给服务端和浏览器端打不同的产物,可以通过打包配置直接做环境隔离,避免运行时判断的不确定性:
- 给webpack浏览器端配置添加别名,忽略
node-localstorage依赖,同时注入环境变量:
// webpack.config.js 浏览器端构建配置 const webpack = require('webpack') module.exports = { resolve: { alias: { 'node-localstorage': false // 浏览器端打包时自动忽略该依赖 } }, plugins: [ new webpack.DefinePlugin({ 'process.env.IS_BROWSER': JSON.stringify(true) }) ] }
- 代码中直接用环境变量做判断:
if (!process.env.IS_BROWSER) { // 仅Node环境会执行这部分代码,浏览器端打包时会被直接摇树移除 const { LocalStorage } = require('node-localstorage') globalThis.localStorage = new LocalStorage('./localStorage') }
内容的提问来源于stack exchange,提问作者user2875404
相关产品推荐
相关产品推荐

