【问题标题】:Error: Can't resolve 'fs' in JS isomorphic app错误:无法解析 JS 同构应用程序中的“fs”
【发布时间】:2019-04-23 12:50:31
【问题描述】:

我正在构建一个应该在前端和后端运行的 Typescript 包。我正在使用这个包来识别环境是浏览器还是节点: https://www.npmjs.com/package/browser-or-node 入口点是单个 index.js 文件

我可以毫无问题地构建和发布应用程序,但是当我导入它并尝试在浏览器中运行它时,我收到错误消息 Module not found: Error: Can't resolve 'fs'

这似乎是因为我正在导入 fs 这是一个节点方法并且浏览器不知道该怎么做。

在这种情况下,避免此问题的最佳做法是什么?如果我不导入该模块,该库就可以正常工作。

我的 package.json:

"license": "MIT",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "scripts": {
    "build": "tsc",
    "test": "mocha -r ts-node/register src/**/*.spec.ts"
  },
  "devDependencies": {
    "@types/chai": "^4.1.7",
    "@types/mocha": "^5.2.6",
    "@types/sinon": "^7.0.11",
    "@types/sinon-chai": "^3.2.2",
    "chai": "^4.2.0",
    "mocha": "^6.1.4",
    "sinon": "^7.3.2",
    "sinon-chai": "^3.3.0",
    "ts-node": "^8.1.0",
    "typescript": "^3.4.4"
  },
  "dependencies": {
    "@types/es6-promise": "^3.3.0",
    "axios": "^0.18.0",
    "browser-or-node": "^1.2.1",
    "dotenv": "^7.0.0"
  }

我的 tsconfig.json:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "declaration": true,
    "outDir": "./dist",
    "strict": true,
    "noImplicitAny": false,
    "lib": [ "es2015" ]
  },
  "exclude":[
    "node_modules",
    "./dist",
    "./**/*.spec.ts",
    "./test/**/*.ts"
  ]
}

导致问题的函数:

import * as fs from 'fs';

export function saveTokensNode(data: any, path: string) {
    try {
        fs.writeFileSync(path, JSON.stringify(data))
    } catch (err) {
        console.error(err)
    }
}

我在哪里使用它:

setCredentials(tokens) {
    if (isBrowser) {
        saveTokensStorage(tokens)
    }

    if (isNode) {
        saveTokensNode(tokens, 'temp/tokensToStore.json')
    }
}

【问题讨论】:

    标签: javascript node.js typescript ecmascript-6


    【解决方案1】:

    基本答案是您可以使用"browser" package.json field 从浏览器包中排除模块。它受到所有主要捆绑软件的支持。

    {
      "browser": {
        "fs": false
      }
    }
    

    然后,在 browserify 中,当你导入 fs 时,你会得到一个空对象。不过,我不确定其他捆绑程序会做什么!


    但您实际上可以稍微不同地执行此操作,并避免需要浏览器或节点包。您可以有两个文件用于令牌存储的节点和浏览器实现。例如,

    // token-storage.js
    import * as fs from "fs"
    export function saveTokens() { /* Node implementation */ }
    
    // token-storage.browser.js
    export function saveTokens() { /* localStorage implementation */ }
    

    您可以在它们之间切换,再次使用“浏览器”字段。

    {
      "browser": {
        "./path/to/token-storage.js": "./path/to/token-storage.browser.js"
      }
    }
    

    然后,在你的模块中,你可以这样做:

    import { saveTokens } from "./token-storage.js"
    function setCredentials (tokens) {
      saveTokens(tokens, 'temp/tokensToStore.json')
    }
    

    浏览器实现可以忽略文件路径,或将其用作本地存储键名。它使节点/浏览器决策本地化到令牌存储文件,当您在其他任何地方使用它时,您不必考虑它。

    【讨论】:

    • 谢谢 它如何与 Typescript 一起工作?因为我猜。 { "browser": { "./path/to/token-storage.js": "./path/to/token-storage.browser.js" } } 我不能传递 .ts 文件吗?
    • 我已经尝试了上述方法,但它似乎对我不起作用..在输出中有两个不同文件的想法是什么?例如“index.js”和“bundle.js”?当我发布库时,正在消费的客户如何知道使用哪一个
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-03
    • 2017-03-15
    • 1970-01-01
    • 2020-07-19
    • 2020-06-23
    • 2017-04-18
    • 2019-12-01
    相关资源
    最近更新 更多