首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使类型记录2路径映射(别名)工作

使类型记录2路径映射(别名)工作
EN

Stack Overflow用户
提问于 2017-02-16 14:31:06
回答 1查看 4.3K关注 0票数 1

我试图引用自定义模块快捷方式(即使用ts路径映射功能)为我的类型记录应用程序,与以下配置。

项目结构

代码语言:javascript
复制
dist/

src/
  lyrics/
     ... ts files
  app/
     ... ts files

完整的项目结构在这里:Github.com/adadgio/npm-歌词-ts,dist文件夹当然是没有完成的)

tsconfig.json

代码语言:javascript
复制
{
    "compilerOptions": {
        "outDir": "dist",
        "module": "commonjs",
        "target": "es6",
        "sourceMap": true,
        "moduleResolution": "node",
        "experimentalDecorators": true,
        "emitDecoratorMetadata": true,
        "removeComments": true,
        "noImplicitAny": false,
        "baseUrl": ".",
        "paths": {
            "*": ["src/lyrics/*"], // to much here !! but none work
            "zutils/*": ["./src/lyrics/*", "src/lyrics/utils/*", "dist/lyrics/utils/*"]
        },
        "rootDir": "."
    },
    "exclude": [
        "dist",
        "node_modules"
    ],
    "include": [
        "src/**/*.ts"
    ]
}

当我运行npm启动/编译或查看脚本时,我不会收到任何类型记录错误。以下工作(Atom是我的IDE)

代码语言:javascript
复制
// string-utils.ts does exist, no IDE error, typescript DOES compile
`import { StringUtils } from 'zutils/string-utils';` 

但是,我得到了下面的NodeJS错误:

代码语言:javascript
复制
Error: Cannot find module 'zutils/string-utils'
    at Function.Module._resolveFilename (module.js:470:15)
    at Function.Module._load (module.js:418:25)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/home/adadgio/WebServer/projects/adadgio/npm-lyrics-ts/src/index.ts:7:1)
    at Module._compile (module.js:571:32)
    at Module.m._compile (/home/adadgio/WebServer/projects/adadgio/npm-lyrics-ts/node_modules/ts-node/src/index.ts:413:23)
    at Module._extensions..js (module.js:580:10)
    at Object.require.extensions.(anonymous function) [as .ts] (/home/adadgio/WebServer/projects/adadgio/npm-lyrics-ts/node_modules/ts-node/src/index.ts:416:12)
    at Module.load (module.js:488:32)

看起来该模块正在尝试从node_modules文件夹中解析。我读过关于类型记录路径映射的文档,但是我无法让它工作。

EN

回答 1

Stack Overflow用户

发布于 2018-06-26 13:51:00

我对此做了很多研究。我用的是原子,打字稿和nodejs。

问题是,当您编译类型记录时,它确实搜索路径(要包含的.ts文件的路径)。但是,最终编译的.js文件不会被路径替换。

解决方案:

  • 编译ts文件,使用tsconfig中的路径。
  • 使用脚本替换最终.js文件中的路径令牌
  • 运行节点应用程序

因此,从本质上讲,tsconfig的部分内容如下所示

代码语言:javascript
复制
  "baseUrl": "./app",
    "paths" : {
      "@GameInstance" : ["model/game/GameInstance"],
      "@Map" : ["model/game/map/Map"],
      "@MapCreator" : ["model/game/map/creator/MapCreator"],
      "@GameLoop" : ["model/game/GameLoop"],
      "@Point" : ["model/other/math/geometry/Point"],
      "@Rectangle" : ["model/other/math/geometry/Rectangle"],
      "@Functions" : ["model/other/Functions"]

    }

并考虑Rectangle.ts文件

代码语言:javascript
复制
import { Point } from '@Point';
import { Vector } from '@Vector';
/**
 * Represents a rectangle.
 * You can query it for collisions or whether rectangles are touching
 */
export class Rectangle {
//more code

Rectangle.ts在哪里

代码语言:javascript
复制
./src/app/model/other/math/geometry/Rectangle/Rectangle.ts

我们跑

代码语言:javascript
复制
tsc

它将编译我们设置的所有.ts文件。在那里,路径将在运行时被替换,如果您有错误,请运行

代码语言:javascript
复制
tsc --traceResolution > tmp && gedit tmp

并且搜索这里的字段是未定义的路径。您将能够看到替换日志。

然后留给我们的是Rectangle.js (构建)

代码语言:javascript
复制
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var _Point_1 = require("@Point");
//more code

正如您所看到的,@Point将不存在,并且我们无法像这样运行节点应用程序。

但是,为此,我创建了一个脚本,它递归地搜索js文件,并通过上升到根,然后到目标路径替换令牌。

在requirePaths.data文件中,您可以定义令牌和路径。

代码语言:javascript
复制
'@GameLoop' : "./app/model/game/GameLoop"
'@GameInstance' : "./app/model/game/GameInstance"
"@Map" : "./app/model/game/map/Map"
"@MapCreator" : "./app/model/game/map/creator/MapCreator"
"@Point" : "./app/model/other/math/geometry/Point"
"@Rectangle" : "./app/model/other/math/geometry/Point"

现在,这不是普遍的,这只是我的热门剧本。请注意,这个结构是

代码语言:javascript
复制
src
|-app
|  |-model
-build
   |-src
      |-app
          |-model
|-test

严格地说,应用程序/模型..。结构,只是将其复制到src/build中,tsc从/ src /app获取源代码并对其进行编译。编译结果在/src/build中。

然后是substitutePathsInJS.sh脚本。这个scand用于构建路径,每当它找到token @矩形时,它就会替换它(更详细的解释如下……)代码:

代码语言:javascript
复制
    #!/bin/bash

function testreqLevel()
{
  local srcPath="$1"
  local replacingIn="$2"
  local expectedLevel=$3
  getPathLevel "$replacingIn"
  local res=$?
  if [ ! $res -eq $expectedLevel ]; then
    echo "[-] test $srcPath , $replacingIn FAILED. ($res != $expectedLevel)"
  fi
}
function assertreqPath()
{
  local input="$1"
  local expected="$2"
  if [ ! "$input" = "$expected" ]; then
    echo "[-] test $expected FAILED"
    echo "computed: $input"
    echo "expected: $expected"
  fi
}
function testGetPathLevel()
{
  testreqLevel "./build/src" "./build/src/app/model/game/GameObject.js" 4
  testreqLevel "./build/src" "./build/src/file.js" 1
  testreqLevel "./build/src" "./build/src/app/model/game/GameObject.js" 4
}
function testGetPathToRoot()
{
  local path=$(getPathToRoot "./build/src" "./build/src/app/model/game/GameObject.js")
  assertreqPath "$path" "../../../../../"

  path=$(getPathToRoot "./" "./server.js")
  assertreqPath "$path" "./"

  path=$(getPathToRoot "./" "./app/model/game/GameInstance.js")
  assertreqPath "$path" "../../../"
}
function err()
{
  echo "[-] $1"
}
function getPathLevel()
{
  #get rid of starting ./
  local input=$(echo "$1" | sed "s/^\.\///")

  local contains=$(echo "$input" | grep '/')
  if [ -z "$contains" ]; then
    return 0
  fi
  #echo "$input"
  local slashInput=$(echo "$input" | awk -F/ '{print NF-1}')
  return $(($slashInput - 1))
}
#given ROOT, and PATH, returns a path P such as being in directory PATH, from there using P we get to root
#example:
#ROOT=./src
#PATH=./src/model/game/objects/a.js
#returns ../../
function getPathToRoot()
{
  local root="$1"
  local input="$2"
  getPathLevel "$input"
  local level=$?

  if [ $level -eq 0 ]; then
    echo "./"
    return 0
  fi
  for ((i=1; i <= level + 1; i++)); do
    echo -n '../'
  done
  #echo "$root" | sed 's/^\.\///'
}
function parseData()
{
echo "**************"
echo "**************"
  local data="$1"

  let lineNum=1
  while read -r line; do
    parseLine "$line" $lineNum
    if [ $? -eq 1 ]; then
      return 1
    fi
    let lineNum++
  done <<< "$data"
  echo 'Parsing ok'

  echo "**************"
  echo "**************"
  return 0
}
function parseLine()
{
  if [[ "$1" =~ ^\#.*$ ]] || [[ "$1" =~ ^\ *$ ]]; then
    #comment line
    return 0
  fi

  local line=$(echo "$1" | sed "s/\"/'/g")
  let lineNum=$2

  local QUOTE=\'
  local WORD_IN_QUOTES=$QUOTE[^:$QUOTE]*$QUOTE

  if [[ "$line" =~ ^\ *$WORD_IN_QUOTES\ *:\ *$WORD_IN_QUOTES\ *$ ]]; then
    # valid key : value pair
    local key=$(echo "$line" | awk -F: '{print $1}' | sed 's/^ *//g' \
    | sed 's/ *$//g' | sed 's/\//\\\//g' | sed "s/'//g" | sed "s/\./\\\./g")
    local val=$(echo "$line" | awk -F: '{print $2}' | sed 's/^ *//g' \
    | sed 's/ *$//g' | sed "s/'//g")
    echo "[+] Found substitution from '$key' : '$val'"

    if [ -z "$REPLACEMENT_KEY_VAL" ]; then
      REPLACEMENT_KEY_VAL="$key|$val"
    else
      REPLACEMENT_KEY_VAL="$REPLACEMENT_KEY_VAL;$key|$val"
    fi
  else
    err "Parse error on line $lineNum"

    echo "Expecting lines 'token' : 'value'"
    return 1
  fi
  return 0
}
function replaceInFiles()
{
  cd "$WHERE_SUBSTITUTE"
  echo "substitution root $WHERE_SUBSTITUTE"

  local fileList=`find . -type f -name "*.js" | grep -v "$EXCLUDE"`

  echo "$fileList"| while read fname; do
    export IFS=";"
    echo "Replacing in file '$WHERE_SUBSTITUTE$fname'"
    for line in $REPLACEMENT_KEY_VAL; do
      local key=`echo "$line" | awk -F\| '{print $1}'`
      local val=`echo "$line" | awk -F\| '{print $2}'`

      local finalPath=$(getPathToRoot "./" "$fname")"$val"

      if [ $VERBOSE -eq 1 ]; then
        echo -e "\tsubstitute '$key' => '$val'"
        #echo -e "\t$finalPath"
        echo -e "\treplacing $key -> $finalPath"
      fi

      #escape final path for sed
      #slashes, dots
      finalPath=$(echo "$finalPath" | sed 's/\//\\\//g'| sed 's/\./\\\./g')

      if [ $VERBOSE -eq 1 ]; then
        echo -e '\t\tsed -i.bak '"s/require(\(.\)$key/require(\1$finalPath/g"\ "$fname"
      fi
      sed -i.bak "s/require(\(.\)$key\(.\))/require(\1$finalPath\2)/g" "$fname"
    done
  done
 return 0
}
function quit()
{
  echo "*************************************"
  echo "*****SUBSTITUTING PATHS EXITING******"
  echo "*************************************"
  echo
  exit $1
}
#######################################
CURRENTDIR=`dirname "$(realpath $0)"`
WHERE_SUBSTITUTE='./build/src'
REPLACEMENT_KEY_VAL="";
VERBOSE=0

FILE="$CURRENTDIR/requirePaths.data"
EXCLUDE='./app/view'

if [ "$1" = "-t" ]; then
  testGetPathLevel
  testGetPathToRoot
  echo "[+] tests done"
  exit 0
fi

if [ "$1" = "-v" ]; then
  VERBOSE=1
fi
echo "*************************************"
echo "********SUBSTITUTING PATHS***********"
echo "*************************************"
if [ ! -f "$FILE" ]; then
  err "File $FILE does not exist"
  quit 1
fi

DATA=`cat "$FILE"`
parseData "$DATA"
if [ $? -eq 1 ]; then
  quit 1
fi
replaceInFiles
quit $?

这似乎令人困惑,但请考虑一下。我们有Rectangle.js文件。

脚本从requirePaths.data文件加载大量输入令牌,在本例中,让我们在线关注

代码语言:javascript
复制
"@Point" : "./app/model/other/math/geometry/Point"

脚本运行于./src,并给出根目录./src/build/src。

脚本做cd ./src/build/src

执行查找。在那里,它会收到

代码语言:javascript
复制
./model/other/math/geometry/Rectangle/Rectangle.ts

它的绝对路径是

代码语言:javascript
复制
./src/build/src/app/model/other/math/geometry/Rectangle/Rectangle.ts

但我们现在不关心绝对的道路。

计算路径,比如他从目录中得到的路径,Whis将得到的结果如下所示

代码语言:javascript
复制
./../../../../

他希望从目录中得到

代码语言:javascript
复制
/src/build/app/model/other/math/geometry/Rectangle

到目录

代码语言:javascript
复制
/src/build/app

然后,在该字符串后面,添加数据文件中提供的路径。

代码语言:javascript
复制
./../../../.././app/model/other/math/geometry/Point

因此,文件Rectangle.js的最后替代(在构建文件夹中的某个位置)是

先于

代码语言:javascript
复制
require("@Point")

代码语言:javascript
复制
require("./../../../.././app/model/other/math/geometry/Point")

这很糟糕,但我们并不关心js中的内容。最重要的是它能工作。

缺点

  1. 您不能将其与代码监视器相结合。监视tsc,然后在完成代码更改时,进行自动tsc编译,然后自动运行shell路径替换,然后对最终的js文件执行tun nodeJS,但由于某种原因,sh脚本替换路径,监视软件认为是代码的更改(不知道为什么,它已经构建排除在监视器之外)并再次编译。因此,您将生成一个无限循环。
  2. 您必须手动编译它,一步一步地编译它,或者只是在tsc编译时使用监视器。编写代码时,运行替换并测试nodeJS功能。
  3. 当添加新的类食物时,必须为它定义一个令牌(@ Food )和路径到文件的两个位置(tsconfig)和shell脚本的输入
  4. 使整个编译过程变得更长。老实说,tsc无论如何都要花费大部分时间,而bash脚本并不是那么费时,令人惊讶的是.
  5. 当使用mocha实现测试时,您必须再次一步一步地编译,当完成后,在最后的js文件上运行mocha。但为此你可以写剧本..。

有些人通常只替换@app或一些目录。问题是,每当你移动源文件时,你必须做很多改变.

好的一面

  1. 在移动文件时,更改一个字符串(在两个位置.)
  2. 不再有使大项目无法维护的相对路径。
  3. 这是有趣的,但它确实有效,我没有遇到重大问题(如果使用得当)。
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42276798

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档