要制作一个npm包,我们需要创建一个新的项目并使用npm初始化该项目。以下是如何使用ts创建npm包的完整例子:
-
创建一个新的文件夹,例如“my-npm-package”,并打开终端进入该目录。
-
输入以下命令初始化npm项目:
npm init -y
这会创建一个默认的package.json文件。
- 安装typescript和@types/node作为开发依赖项:
npm install typescript @types/node --save-dev
-
在项目根目录中创建一个名为“src”的文件夹,并在其中创建一个名为“index.ts”的文件。在这个文件中编写你的ts代码。
-
在package.json文件中添加一些必要的字段如下:
{
"name": "my-npm-package",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc"
}
}
这里我们定义了包名,版本号及入口文件,以及将typescript编译成.js和.d.ts文件的build脚本。
- 在项目根目录中创建一个名为“tsconfig.json”的文件,并添加以下内容(可以根据自己的需要自定义):
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"outDir": "./dist",
"rootDir": "./src",
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"]
}
这里我们定义了编译选项和文件的目录。
- 在package.json文件中添加一个“prepublishOnly”脚本,以确保在发布npm包之前可以先build一下:
{
"scripts": {
"prepublishOnly": "npm run build"
}
}
- 构建npm包:
npm run build
这将使用tsc编译您的TS代码并生成JavaScript和.d.ts文件并存放到dist文件夹中。
- 最后,在npm上发布该包:
npm login
npm publish
这将发布您的npm包到npm仓库中。
这是一个简单的npm包例子,你可以根据自己的需求添加和调整。
作为一个简单的例子,我们可以在index.ts中输出一个函数,函数的作用是把一个数字加1。以下是index.ts的代码示例:
export function addOne(num: number): number {
return num + 1;
}
console.log(addOne(3)); // 输出4
这里我们使用了ES6模块语法导出一个名为“addOne”的函数,并在最后打印了该函数的返回值。在这个例子中,我们简单地输出了一个函数,但你可以写复杂的逻辑或是添加更多的函数和类。
如果使用tsc编译typescript文件(.ts)生成的JavaScript代码,这些代码将不是常规的JavaScript代码,而是经过ECMAScript 6(ES6)转换后的代码(例如ES6类,箭头函数等)。如果使用tsc生成的JavaScript文件,由于浏览器和node.js的不同版本可能不支持一些ES6语法,因此不能在所有情况下正常工作。
为了解决这个问题,我们可以使用babel来转换我们的JavaScript代码,以便能够在不同的环境中运行。转换后的JavaScript代码将通常被称为“transpiled”代码,它与原始JavaScript代码相比可能看起来有些不同,但运行起来是一样的。
要使用babel来设置项目,我们首先需要在项目中安装必要的依赖项:
npm install @babel/preset-env babel-loader @babel/core --save-dev
然后需要在项目中创建一个.babelrc文件,其中包含我们的babel配置:
{
"presets": [
["@babel/preset-env", {
"targets": {
"node": "current"
}
}]
]
}
这里我们使用了@babel/preset-env预设,以便根据目标环境的不同来自动应用转换。
使用babel编译typescript和ES6代码可以在我们的项目中使用webpack。webpack将帮助我们生成包含所有必要文件的打包文件。在这个例子中,在webpack.config.js中添加以下内容:
const path = require('path');
module.exports = {
entry: './src/index.ts',
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.js$/,
use: ['source-map-loader'],
enforce: 'pre',
},
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'umd',
},
};
这里我们定义了一个入口文件、使用babel-loader加载.ts和.tsx文件、exclude了node_modules文件夹、使用source-map-loader hint工具生成source-map文件、输出文件名和路径、和保证包可以在amd、commonjs和全局变量中使用。
然后最后在package.json文件中的scripts项中配置build脚本:
{
"scripts": {
"build": "webpack --config webpack.config.js"
}
}
这样我们构建的npm包生成的JavaScript代码就是经过babel转换后的规范代码了。
在构建npm包时,由于需要将typescript代码编译成JavaScript,并在发布时包含JavaScript文件,因此大多数情况下需要添加source map以便在调试时使用。source map是一系列JavaScript及其源文件的映射,它们帮助调试器了解混淆后的代码如何映射到原始的未混淆的代码中。在开发环境中使用source map是很方便的,但是它会在一定程度上增加构建文件的大小。
为了在构建npm包时包含source map,我们可以在tsconfig.json文件中添加"sourceMap": true配置:
{
"compilerOptions": {
"sourceMap": true,
"outDir": "dist"
// ...
},
// ...
}
这个配置项将在构建npm包时为生成的JavaScript文件生成相应的source map文件,并在调试时使用。另外,也可以在webpack的配置文件中添加devtool选项来生成source map:
module.exports = {
// ...
devtool: 'source-map',
// ...
};
这个选项将使webpack使用source map生成器在编译时生成source map文件。同样,这样做可以在调试npm包时更方便。
在TypeScript中,模块导入默认导出的语法与普通导出的语法有所不同。使用关键字default
导出模块的方式是:
// foo.ts
export default function foo() { /* ... */ }
// bar.ts
import foo from './foo';
foo(); // 调用默认导出的foo函数
默认导出的模块只能导出一个值,而且在导入时使用关键字default
来表示默认导出的值。在使用默认导出时,不需要使用花括号来包裹导入值,直接使用变量即可。在导入时可以将默认导出值放在一个对象中,在使用时使用对象的键来访问。
除了默认导出,还可以使用命名导出和命名空间导出:
// util.ts
export function foo() { /* ... */ }
export const bar = 'bar';
// baz.ts
import { foo, bar } from './util';
foo(); // 调用导出的foo函数
console.log(bar); // 输出bar
// qux.ts
import * as utils from './util';
utils.foo(); // 调用导出的foo函数
console.log(utils.bar); // 输出bar
在上面的示例中,我们导出了两个值(函数foo()
和变量bar
),并通过命名导出的方式使用它们。在导入时,我们使用花括号将命名导出的变量或函数包裹,或使用命名空间来导入整个模块。如果使用命名空间导入模块,需要使用utils.
语法来调用导出的函数和变量。
需要注意的是,当导入默认导出时,导入名可以是任何名称,因为只有一个默认导出。另外,不能使用直接导入的方式同时导入默认导出和命名导出的值,需要分别导入。
// quux.ts
import defaultExport, { namedExport } from './myModule'; // 不被允许的方式
import exportedValue from './myModule'; // 正确的方式(只导出了一个默认值)
import * as myModule from './myModule'; // 正确的方式