如何使用 JSPM 导入带有 Typescript 声明的外部 NPM 模块
How to import external NPM module with Typescript declarations using JSPM
'test-module' 是用 Typescript 编写的带有 index.d.ts 定义文件的外部模块。它在 package.json:
中具有 tsd/tsc 的属性
"typings": "dist/index.d.ts",
"typescript":{
"definition": "dist/index.d.ts"
}
'test-module' 在 jspm_packages/npm/test-module 中与 JSPM 一起安装,用于使用 SystemJS
进行动态加载
'app' 是像这样导入 'test-module' 的 Typescript 应用程序:
从 'test-module' 导入 {组件};
问题是 'test-module' 模块必须位于两个位置:
in node_modules 用于 Typescript 编译器(否则它不会找到 'test-module' 并在从 [=65 编译导入期间出错=])
in jspm_packages 以便 SystemJS 在运行时加载它
所以,我需要将它插入 package.json 'dependencies' AND 'jspm/dependencies'
是否有破解方法:
A) 强制 JSPM/SystemJS 仅使用标准 node_modules 文件夹? (我知道我可以使用原始 SystemJS 和映射 node_modules 但这意味着我必须为每个依赖项和依赖项的依赖项映射它,这是大量的手动工作)
或
B) 强制 Typescript 使用某种路径映射来搜索模块(我猜 1.8 版会有这个功能)
有什么想法吗?
这是我不喜欢的答案,但可以解决。事实上,我在寻找我的案例的答案时遇到了你的问题,它们很相似。
在我的例子中,我也创建了一个外部库,该库是用打字稿编译的,生成的模块可在外部 jspm 项目中使用。
对我有用的是使用与 javascript es6 相同的语法导入库。假设该库名为 myLib 并且有一个 myLib=blabla 的 config.js 映射,并且您有一个名为 notify.js 的文件(从打字稿生成)。进口是
import Notify from 'myLib/notify'
在运行时它可以工作,但问题是项目的编译器无法找到 'myLib/notify'。由 typescript (file jspm_package/github/myLib/myLib@version/notify.d.ts 为库生成的定义类似于:
export declare enum NotifyStatus {
INFO = 0,
SUCCESS = 1,
WARNING = 2,
DANGER = 3,
}
export declare enum NotifyPosition {
TOP_CENTER = 0,
TOP_LEFT = 1,
TOP_RIGHT = 2,
BOTTOM_CENTER = 3,
BOTTOM_LEFT = 4,
BOTTOM_RIGHT = 5,
}
/**
* Class for notifications
*/
export declare class Notify {
/**
* Show a default Notification in the page
* @param {string} message The message
* @param {NotifyStatus = NotifyStatus.INFO} status Status to style the message
* @param {[type]} timeout=5000 Timeout
* @param {NotifyPosition = NotifyPosition.TOP_CENTER} pos Position to display the message
* @return {NotifyMessage} A object representing the message on the DOM
*/
static show(message: string, status?: NotifyStatus, timeout?: number, pos?: NotifyPosition): NotifyMessage;
private static getStatusString(status);
private static getPositionString(position);
}
export interface DialogModal {
show(): any;
hide(): any;
}
为了解决这个问题,我手动修改了库声明中的定义包装:
declare module 'myLib/notify' {
export declare enum NotifyStatus {
INFO = 0,
SUCCESS = 1,
WARNING = 2,
DANGER = 3,
}
export declare enum NotifyPosition {
TOP_CENTER = 0,
TOP_LEFT = 1,
TOP_RIGHT = 2,
BOTTOM_CENTER = 3,
BOTTOM_LEFT = 4,
BOTTOM_RIGHT = 5,
}
/**
* Class for notifications
*/
export declare class Notify {
/**
* Show a default Notification in the page
* @param {string} message The message
* @param {NotifyStatus = NotifyStatus.INFO} status Status to style the message
* @param {[type]} timeout=5000 Timeout
* @param {NotifyPosition = NotifyPosition.TOP_CENTER} pos Position to display the message
* @return {NotifyMessage} A object representing the message on the DOM
*/
static show(message: string, status?: NotifyStatus, timeout?: number, pos?: NotifyPosition): NotifyMessage;
private static getStatusString(status);
private static getPositionString(position);
}
export interface DialogModal {
show(): any;
hide(): any;
}
}
我的 tsconfig.json 文件配置为在 jspm_packages 中查找定义
然后编译停止警告,Atom 编辑器提供智能感知。
这种方法有两个问题:
- 包裹是
手动(这很烦人)
- myLib在定义中是手写的,其他位置不能改,必须用import 'myLib/bla',实际上'myLib'即可被 SystemJS 和 jspm 覆盖到其他参考。
我正在搜索的是一种使用模块声明自动生成打字稿定义的方法。
我遇到了这个https://www.npmjs.com/package/autodts但我不完全理解它是如何工作的,但它可以用来以这种方式自动生成定义文件。
编辑:
我创建了一个 gulp 任务来编辑打字稿定义文件并添加自动添加 声明模块 。方法如下:
var gulp = require('gulp');
var runSequence = require('run-sequence');
var ts = require('gulp-typescript');
var paths = require('../paths');
var through2 = require('through2');
var concat = require('gulp-concat');
var insert = require('gulp-insert');
var rename = require('gulp-rename');
var merge = require('merge2');
var modify = require('gulp-modify');
var tsProjectAmd = ts.createProject('tsconfig.json', {module: 'amd'});
var tsProjectES6 = ts.createProject('tsconfig.json', {module: 'es6'});
var tsProjectCOMMONJS = ts.createProject('tsconfig.json', {module: 'commonjs'});
var tsProjectSystem = ts.createProject('tsconfig.json', {module: 'system'});
var makeBuild = function(project, format, path, output){
return function(){
var tsResult = gulp.src(path)
.pipe(ts(project));
return merge([
tsResult.js.pipe(gulp.dest(output + format)),
tsResult.dts.pipe(modify({
fileModifier: function(file, content){
// Split at /dist/ caracter
var regex = new RegExp("/" + paths.dist);
var split = file.path.split(regex);
// Remove ".d.ts";
var fileNameAndPath = split[1].slice(0, split[1].length - 5);
if(fileNameAndPath != paths.packageName){
return 'declare module "' + paths.packageName + "/" + fileNameAndPath + '" {\n' + content + '\n}';
}else {
return content;
}
}
})).pipe(gulp.dest(output + format))
]);
}
}
gulp.task('build-amd', makeBuild(tsProjectAmd, '', paths.source, paths.output));
paths.js
var path = require('path');
var fs = require('fs');
var appRoot = 'src/';
var outputRoot = 'dist/src/';
var pkg = JSON.parse(fs.readFileSync('./package.json', 'utf-8'));
module.exports = {
root: appRoot,
source: [appRoot + '**/*.ts','typings/**/*.ts'],
html: appRoot + '**/*.html',
style: outputRoot + 'css/**/*.css',
styles: outputRoot + 'css/',
less: ['less/theme/**/*.less','!less/theme/_variables.less'],
fonts: 'less/uikit/src/fonts/*',
images: 'images/**/*',
output: outputRoot,
doc:'./docs',
apiDoc: './api-doc',
dist: 'dist/',
testsFixtures: 'test/fixtures/*',
specsSrc: 'test/**/*.ts',
specsOutput: 'dist/',
packageName: pkg.name
};
'test-module' 是用 Typescript 编写的带有 index.d.ts 定义文件的外部模块。它在 package.json:
中具有 tsd/tsc 的属性"typings": "dist/index.d.ts", "typescript":{ "definition": "dist/index.d.ts" }
'test-module' 在 jspm_packages/npm/test-module 中与 JSPM 一起安装,用于使用 SystemJS
进行动态加载
'app' 是像这样导入 'test-module' 的 Typescript 应用程序:
从 'test-module' 导入 {组件};
问题是 'test-module' 模块必须位于两个位置:
in node_modules 用于 Typescript 编译器(否则它不会找到 'test-module' 并在从 [=65 编译导入期间出错=])
in jspm_packages 以便 SystemJS 在运行时加载它
所以,我需要将它插入 package.json 'dependencies' AND 'jspm/dependencies'
是否有破解方法:
A) 强制 JSPM/SystemJS 仅使用标准 node_modules 文件夹? (我知道我可以使用原始 SystemJS 和映射 node_modules 但这意味着我必须为每个依赖项和依赖项的依赖项映射它,这是大量的手动工作)
或
B) 强制 Typescript 使用某种路径映射来搜索模块(我猜 1.8 版会有这个功能)
有什么想法吗?
这是我不喜欢的答案,但可以解决。事实上,我在寻找我的案例的答案时遇到了你的问题,它们很相似。
在我的例子中,我也创建了一个外部库,该库是用打字稿编译的,生成的模块可在外部 jspm 项目中使用。
对我有用的是使用与 javascript es6 相同的语法导入库。假设该库名为 myLib 并且有一个 myLib=blabla 的 config.js 映射,并且您有一个名为 notify.js 的文件(从打字稿生成)。进口是
import Notify from 'myLib/notify'
在运行时它可以工作,但问题是项目的编译器无法找到 'myLib/notify'。由 typescript (file jspm_package/github/myLib/myLib@version/notify.d.ts 为库生成的定义类似于:
export declare enum NotifyStatus {
INFO = 0,
SUCCESS = 1,
WARNING = 2,
DANGER = 3,
}
export declare enum NotifyPosition {
TOP_CENTER = 0,
TOP_LEFT = 1,
TOP_RIGHT = 2,
BOTTOM_CENTER = 3,
BOTTOM_LEFT = 4,
BOTTOM_RIGHT = 5,
}
/**
* Class for notifications
*/
export declare class Notify {
/**
* Show a default Notification in the page
* @param {string} message The message
* @param {NotifyStatus = NotifyStatus.INFO} status Status to style the message
* @param {[type]} timeout=5000 Timeout
* @param {NotifyPosition = NotifyPosition.TOP_CENTER} pos Position to display the message
* @return {NotifyMessage} A object representing the message on the DOM
*/
static show(message: string, status?: NotifyStatus, timeout?: number, pos?: NotifyPosition): NotifyMessage;
private static getStatusString(status);
private static getPositionString(position);
}
export interface DialogModal {
show(): any;
hide(): any;
}
为了解决这个问题,我手动修改了库声明中的定义包装:
declare module 'myLib/notify' {
export declare enum NotifyStatus {
INFO = 0,
SUCCESS = 1,
WARNING = 2,
DANGER = 3,
}
export declare enum NotifyPosition {
TOP_CENTER = 0,
TOP_LEFT = 1,
TOP_RIGHT = 2,
BOTTOM_CENTER = 3,
BOTTOM_LEFT = 4,
BOTTOM_RIGHT = 5,
}
/**
* Class for notifications
*/
export declare class Notify {
/**
* Show a default Notification in the page
* @param {string} message The message
* @param {NotifyStatus = NotifyStatus.INFO} status Status to style the message
* @param {[type]} timeout=5000 Timeout
* @param {NotifyPosition = NotifyPosition.TOP_CENTER} pos Position to display the message
* @return {NotifyMessage} A object representing the message on the DOM
*/
static show(message: string, status?: NotifyStatus, timeout?: number, pos?: NotifyPosition): NotifyMessage;
private static getStatusString(status);
private static getPositionString(position);
}
export interface DialogModal {
show(): any;
hide(): any;
}
}
我的 tsconfig.json 文件配置为在 jspm_packages 中查找定义
然后编译停止警告,Atom 编辑器提供智能感知。
这种方法有两个问题:
- 包裹是
手动(这很烦人) - myLib在定义中是手写的,其他位置不能改,必须用import 'myLib/bla',实际上'myLib'即可被 SystemJS 和 jspm 覆盖到其他参考。
我正在搜索的是一种使用模块声明自动生成打字稿定义的方法。
我遇到了这个https://www.npmjs.com/package/autodts但我不完全理解它是如何工作的,但它可以用来以这种方式自动生成定义文件。
编辑:
我创建了一个 gulp 任务来编辑打字稿定义文件并添加自动添加 声明模块 。方法如下:
var gulp = require('gulp');
var runSequence = require('run-sequence');
var ts = require('gulp-typescript');
var paths = require('../paths');
var through2 = require('through2');
var concat = require('gulp-concat');
var insert = require('gulp-insert');
var rename = require('gulp-rename');
var merge = require('merge2');
var modify = require('gulp-modify');
var tsProjectAmd = ts.createProject('tsconfig.json', {module: 'amd'});
var tsProjectES6 = ts.createProject('tsconfig.json', {module: 'es6'});
var tsProjectCOMMONJS = ts.createProject('tsconfig.json', {module: 'commonjs'});
var tsProjectSystem = ts.createProject('tsconfig.json', {module: 'system'});
var makeBuild = function(project, format, path, output){
return function(){
var tsResult = gulp.src(path)
.pipe(ts(project));
return merge([
tsResult.js.pipe(gulp.dest(output + format)),
tsResult.dts.pipe(modify({
fileModifier: function(file, content){
// Split at /dist/ caracter
var regex = new RegExp("/" + paths.dist);
var split = file.path.split(regex);
// Remove ".d.ts";
var fileNameAndPath = split[1].slice(0, split[1].length - 5);
if(fileNameAndPath != paths.packageName){
return 'declare module "' + paths.packageName + "/" + fileNameAndPath + '" {\n' + content + '\n}';
}else {
return content;
}
}
})).pipe(gulp.dest(output + format))
]);
}
}
gulp.task('build-amd', makeBuild(tsProjectAmd, '', paths.source, paths.output));
paths.js
var path = require('path');
var fs = require('fs');
var appRoot = 'src/';
var outputRoot = 'dist/src/';
var pkg = JSON.parse(fs.readFileSync('./package.json', 'utf-8'));
module.exports = {
root: appRoot,
source: [appRoot + '**/*.ts','typings/**/*.ts'],
html: appRoot + '**/*.html',
style: outputRoot + 'css/**/*.css',
styles: outputRoot + 'css/',
less: ['less/theme/**/*.less','!less/theme/_variables.less'],
fonts: 'less/uikit/src/fonts/*',
images: 'images/**/*',
output: outputRoot,
doc:'./docs',
apiDoc: './api-doc',
dist: 'dist/',
testsFixtures: 'test/fixtures/*',
specsSrc: 'test/**/*.ts',
specsOutput: 'dist/',
packageName: pkg.name
};