【问题标题】:Using NPM Modules in Namespaced Typescript project在命名空间 Typescript 项目中使用 NPM 模块
【发布时间】:2021-01-22 07:40:24
【问题描述】:

我有一个项目(现有项目),其前端是用命名空间打字稿编写的。 我无法将所有打字稿文件从命名空间方法重写为导出/导入 es6 语法。

但是下面的代码运行良好。如果我添加我的新 ts 模块或反应组件,我将它包装在命名空间中并通过类或命名空间前缀调用它,如果它在其他命名空间中,则没有问题。

问题是我不能使用带有 import 语句的外部模块。我该如何使用..?因为 import 语句抛出错误。

为了更具体地了解下面的代码,我想使用 react-redux,

当我检查 node_moduels 文件夹时,我看到了引用 React 命名空间的 @types 文件夹 我假设由于 tsconfig 中的这一行

"typeRoots": [
      "./node_modules/@types/"
    ]

但是当我安装npm install --save @types/react-redux 时,它还在节点模块的@types 文件夹下创建了带有index.ts 的react-redux 文件夹。但它没有命名空间导出行,React 类型文件如何具有以下内容。

export as namespace React;

declare namespace React {
....
}

最终..我如何在这个项目中使用第三方节点模块,尤其是 react-redux。 或任何简单的节点模块并在任何 ts 文件简单模块中访问它,例如“react-bootstrap” 下面是包含在命名空间中的反应组件的简单 ts 文件,它工作正常(导入状态除外)

import { createStore } from 'redux'; //if i add this line this is throwing error.

namespace Profile.Sample {

    import { createStore } from 'redux'; //this too throwing error, without these lines my code is working fine.
    export class Profiles extends React.Component<any> {

        constructor(props) {
            super(props);           
            this.state = { brand: "Ford" };

        }     

        render(): React.ReactNode {

            return (
                <sect
                    <div className="container-fluid">
                        <div className="row">
                            <div className="col-lg-12">
                                <div className="main-title">
                                    <h2>Profiles</h2>
                                    <p>Lorem ipsum dolor sit amet, consectetur adi</p>
                                </div>
                            </div>
                        </div>
                        
                    </div>
                </section>

            );
        }
    }
}

下面是我的 tsconfig

{
  "compileOnSave": true,
  "compilerOptions": {
    "preserveConstEnums": true,
    "experimentalDecorators": true,
    "declaration": true,
    "emitBOM": true,
    "jsx": "react",
    "noEmitHelpers": true,
    "inlineSourceMap": true,
    "inlineSources": true,
    "outFile": "wwwroot/Scripts/site/Profiles.js",
    "skipLibCheck": true,
    "skipDefaultLibCheck": true,
    "target": "es5",
    "typeRoots": [
      "./node_modules/@types/"
    ]
  }
}

我知道命名空间不是未来推荐的方法。但这是一个现有项目,无法将命名空间中的所有文件重写为导入/导出语句。

【问题讨论】:

  • 您是否将您的代码与任何捆绑程序捆绑在一起——webpack、rollup、parcel?
  • 不,只是build js在项目主文件中作为脚本调用
  • tsconfig.json 文件是固定的还是可修改的?
  • 它可以修改..但现有代码不应该破坏。

标签: reactjs typescript react-redux typescript-typings typescript2.0


【解决方案1】:

好的,让我们一步一步让它可运行:

  1. 虽然您没有明确说明,但我假设您收到错误消息Cannot compile modules using option 'outFile' unless the '--module' flag is 'amd' or 'system'.。选项outFile 生成一个主文件,其中包含您的所有代码。由于您在tsconfig.json 中使用"target": "es5",因此module 的默认值为commonjscommonjs 是 node.js (var x = require('x') / exports.x = x) 广泛使用的模块语法,该语法不支持将代码合并到一个文件中,因此被禁止。但是您想在浏览器中使用您的代码,因此无论如何都不支持commonjs。所以首先要做的是

    "module": "AMD" 插入到您的tsconfig.json 文件中。

    AMD 是一种可在浏览器中使用的模块语法。也可以使用"UMD",只是一个扩展,让模块支持AMDcommonjs模块。

  2. 为避免稍后进行更多配置,您还应该

    在您的 tsconfig.json 文件中将 "outFile": "wwwroot/Scripts/site/Profiles.js" 更改为 "outDir": "wwwroot/Scripts/site"

  3. module 设置为AMD 会将moduleResolution 的默认值从node 更改为classic,但这并不好,因为那样import {createStore} from 'redux' 将失败并显示错误消息Cannot find module 'redux'. Did you mean to set the 'moduleResolution' option to 'node', or to add aliases to the 'paths' option?。因此

    "moduleResolution": "node" 包含到您的tsconfig.json 文件中。

  4. 在您的代码中,您定义了一个扩展另一个基类的类。如果您转译此继承,则需要一个特殊函数 __extends。在当前设置下,此函数不是由 typescript 生成的,您会收到错误 Uncaught ReferenceError: __extends is not defined。因此

    删除"noEmitHelpers": true

  5. 现在您的所有文件都可以转译为 AMD 模块。但是要使用这些模块,您需要一个模块加载器。最受欢迎的是require.js。要使用它,

    &lt;script data-main="setup" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"&gt;&lt;/script&gt; 插入到您的 HTML 文件中。

    您也可以download 自己服务。 data-main="setup" 表示加载完 require.js 后,会执行脚本 setup.js。此脚本将在下一步中创建。

  6. require.js 需要一些配置才能找到所有模块。所以

    创建wwwroot\Scripts\site\setup.js:

    requirejs.config({
      appDir: ".",
      paths: { 
        'react': ['./node_modules/react/umd/react.production.min.js', 'https://unpkg.com/react@16/umd/react.production.min'],
        'react-dom': ['./node_modules/react-dom/umd/react-dom.production.min.js', 'https://unpkg.com/react-dom@16/umd/react-dom.production.min'],
        'redux': ['./node_modules/redux/dist/redux.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min'],
      },
    });
    
    requirejs(['entryPoint'], function() {
      console.log("Entry point 'index' has been loaded!");
      return {};
    });
    

    在第一部分配置了require.js。特别是,定义了外部模块(通过npm 安装的模块)的位置。这里reactreact-domredux 的位置设置为node_modules 文件夹中的位置,其中包含来自内容交付网络(CDN) 的外部文件作为备份。您也可以删除其中一个位置。他们从左到右被请求,如果一个请求失败则继续。如果您使用 node_modules 文件夹中的位置,您也必须从您的网络服务器提供它们!

    在第二部分中,模块entryPoint 被执行。这是您的应用程序的入口点。将名称更改为您希望作为入口点的任何名称。如果您希望文件someOtherFile.js 中定义的模块作为入口点,请编写requirejs(['someOtherFile'], ...

  7. 转译所有文件运行

    tsc --project tsconfig.json.

  8. 提供目录wwwroot/Scripts/site 中的所有文件,包括您的HTML 文件。出于测试目的,您可以使用

    npx serve.

您可以在此处查看稍作修改的代码:https://codesandbox.io/s/elated-fermat-ie2ms?file=/src/index.tsx

【讨论】:

  • 非常感谢您出色的分步说明。两件事,1)我不能从上述方法创建一个 js 文件并避免需要一个入口点。考克斯我正在努力设置入口点。 2)当我将“导出”添加到现有命名空间时,例如导出命名空间 Profile.Sample { ....},它开始为其他命名空间抛出错误。“找不到命名空间 XYZ”,例如。而且我的命名空间都没有项目中的导出前缀
  • 1) 即使您转译为单个文件,您也必须定义一个入口点。此入口点定义了启动时运行的内容。没有入口点 = 没有要运行的代码。 2)我实际上忘记了这个,我添加了export用于测试目的。如果您不导出命名空间,那么您也无法导入其中的所有内容。那么如何在代码中管理命名空间呢?你只有一个命名空间吗?
  • 再次感谢@Peter,有 2-3 个,当需要从另一个命名空间访问时,每个都使用命名空间前缀调用。问题是如何在不导出命名空间的情况下引用外部库。原因是我添加“导出”所引用的命名空间前缀的那一刻开始抛出错误。只有一个根命名空间和多个子命名空间。例如,Profiles.Agent 命名空间中的代码可以毫无问题地引用 Profiles.Client 命名空间中的类。并且 nodemodules/@types 中的任何命名空间也可以被引用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-30
  • 2016-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-14
  • 2016-07-18
相关资源
最近更新 更多