通用打字稿 npm 模块
Universal typescript npm module
我正在修改一个现有的库,以便它可以在打字稿中导入。我把它归结为 Minimal working example
要求
- 为了保持向后兼容,需要使用简单的
<script>
标签导入库
- 为了简化将来的使用,需要使用单个打字稿
import
语句导入库(不需要 HTML 中的 <script>
标签)
- 我使用过汇总,但也欢迎使用任何其他方式(gulp、webpack 等)来实现此结果的解决方案。
到目前为止我得到了什么
图书馆
文件结构:
│ package.json
│ rollup.config.js
│ tsconfig.json
│ yarn-error.log
│ yarn.lock
│
└───src
lib.ts
options.ts
package.json
:
{
"name": "library",
"version": "1.0.8",
"description": "example library",
"main": "dist/lib.umd.js",
"module":"dist/lib.esm.js",
"types":"dist/types/lib.d.ts",
"license": "MIT",
"private": true,
"devDependencies": {
"@rollup/plugin-typescript": "^8.3.0",
"rollup": "^2.67.0",
"tslib": "^2.3.1",
"typescript": "^4.5.5"
},
"exports": {
"import": "./dist/lib.esm.js",
"require": "./dist/lib.umd.js"
},
"scripts": {
"build:types": "tsc -d --emitDeclarationOnly",
"build:js": "rollup -c rollup.config.js",
"build:minjs:umd": "terser dist/index.umd.js --compress --mangle > dist/index.umd.min.js",
"build:minjs:esm": "terser dist/index.esm.js --compress --mangle > dist/index.esm.min.js",
"build:minjs": "npm run build:minjs:esm -s && npm run build:minjs:umd -s",
"build": "npm run build:js -s && npm run build:minjs -s && npm run build:types -s",
"prepublishOnly": "npm run lint -s && npm test -s && npm run build",
"semantic-release": "semantic-release"
},
"type":"module"
}
rollup.config.js
:
import typescript from '@rollup/plugin-typescript';
export default {
input: 'src/lib.ts',
output: [
{
file: 'dist/lib.esm.js',
format: 'es',
},
{
file: 'dist/lib.umd.js',
format: 'umd',
name: 'Lib',
},
],
plugins: [typescript({tsconfig:'./tsconfig.json'})],
};
tsconfig.json
:
{
"compilerOptions": {
"target": "es2016",
"module": "esnext",
"moduleResolution": "node",
"declaration": true,
"outDir": "./types",
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
}
src/lib.ts
:
import Options from "./options";
export default class Lib{
constructor(options:Options){
console.log("It works!");
console.log(options.message);
}
}
options.ts
:
export default interface Options {
message: string;
}
我正在使用 yarn build:js
.
编译所有这些
使用图书馆
有 <script>
个标签
当我将生成的 lib.umd.js
复制到文件夹并创建 index.html
:
<script src=lib.umd.js></script>
<script>
var a = new Lib({message:"message here"});
</script>
有效。到目前为止一切顺利。
在另一个打字稿项目中
接下来,我创建了一个使用我的库的简单打字稿项目。
文件结构:
│ gulpfile.js
│ package.json
│ tsconfig.json
│ yarn.lock
│
├───dist
│ index.html
│
└───Scripts
Index.ts
在 package.json
中,我将我的库作为依赖项,连同 jQuery 以希望排除该项目的不正确配置:
{
"private": true,
"version": "1.0.0",
"scripts": {
"preinstall": "npx use-yarn",
"gulp": "node_modules/.bin/gulp"
},
"name": "ts-import",
"devDependencies": {
"@types/jquery": "^3.5.13",
"gulp": "^4.0.2",
"gulp-browserify": "^0.5.1",
"gulp-clean": "^0.4.0",
"gulp-concat": "^2.6.1",
"gulp-sourcemaps": "^3.0.0",
"gulp-typescript": "^6.0.0-alpha.1",
"gulp-uglify": "^3.0.2",
"typescript": "^4.5.5",
"vinyl-source-stream": "^2.0.0"
},
"dependencies": {
"jquery": "*",
"library": "file:../../library"
}
}
tsconfig.json
:
{
"compilerOptions": {
"noEmitOnError": true,
"noImplicitAny": true,
"sourceMap": true,
"target": "es5",
"moduleResolution": "node",
"outDir":"./js"
},
"compileOnSave": true,
"exclude": [
"**/node_modules/**"
],
"include":[
"./Scripts"
]
}
我正在使用 gulp 编译 ts 和解析导入 - gulpfile.js
:
const gulp = require('gulp');
const {series} = require('gulp');
const clean = require('gulp-clean');
const ts = require('gulp-typescript');
const sourcemaps = require('gulp-sourcemaps');
const browserify = require('gulp-browserify');
const concat = require('gulp-concat');
const uglify = require('gulp-uglify');
function cleanAll(cb) {
return gulp.src([
"./tmp/",
"./dist/js"
], { read: false, allowEmpty: true })
.pipe(clean());
}
function transpileTS() {
const tsproject = ts.createProject('./tsconfig.json');
return tsproject
.src()
.pipe(sourcemaps.init())
.pipe(tsproject()).js
.pipe(sourcemaps.write('./sourcemaps'))
.pipe(gulp.dest('./tmp/js'));
}
function minJS() {
return gulp
.src('./tmp/js/Index.js')
.pipe(sourcemaps.init({ loadMaps: true }))
.pipe(browserify())
// .pipe(uglify())
.pipe(concat('index.min.js'))
.pipe(sourcemaps.write('./sourcemaps'))
.pipe(gulp.dest('./dist/js'))
}
exports.default = series( cleanAll, transpileTS, minJS );
我正在像这样导入和使用我的库 - Scripts/Index.ts
:
import * as $ from "jquery";
import Lib from "library";
$(()=>{
console.log("creating lib instance.");
new Lib({message:"example message here"});
});
但是当我在浏览器中启动它时 - dist/index.html
:
<script src="js/Index.min.js"></script>
我得到一个错误:
Uncaught TypeError: library_1.default is not a constructor
的确,library_1.default
不存在,library_1
确实存在:
> library_1
< class Lib {
constructor(options) {
console.log("It works!");
console.log(options.message);
}
}
我该如何解决这个问题?我怀疑错误是在图书馆的某个地方,但我不知道在哪里。
我已经弄明白了。
在我的 lib.ts
中,我不得不更改导出 class:
的方式
import Options from "./options";
class Lib{
constructor(options:Options){
console.log("It works!");
console.log(options.message);
}
}
export default Lib;
接下来,我更改了 rollup.config.js
(添加了 exports:'default'
)以保持导出的 class 全局:
...
{
file: 'dist/lib.umd.js',
format: 'umd',
name: 'Lib',
exports:'default'
},
...
我还必须更改库的 package.json
- 我将 main
指向我的 es 模块,因为它看起来像 browserify 只是忽略了模块指令。
我还最终删除了 exports
部分,因为我们的一些其他项目(不使用 browserify)继续使用 require
文件,而不是 import
文件:
{
"name": "library",
"version": "1.0.16",
"description": "example library",
"main": "dist/lib.esm.js",
"module":"dist/lib.esm.js",
"types":"dist/types/lib.d.ts",
"license": "MIT",
"private": true,
"devDependencies": {
"@rollup/plugin-typescript": "^8.3.0",
"rollup": "^2.67.0",
"tslib": "^2.3.1",
"typescript": "^4.5.5"
},
"exports": {
"import": "./dist/lib.esm.js",
"require": "./dist/lib.umd.js"
},
"scripts": {
"build": "rollup -c rollup.config.js"
}
}
最后,我不得不在我的消费者项目中使用 babelify 来避免 ParseError: 'import' and 'export' may appear only with 'sourceType: module'
而 运行 browserify。
完整的源代码可用here
我正在修改一个现有的库,以便它可以在打字稿中导入。我把它归结为 Minimal working example
要求
- 为了保持向后兼容,需要使用简单的
<script>
标签导入库 - 为了简化将来的使用,需要使用单个打字稿
import
语句导入库(不需要 HTML 中的<script>
标签) - 我使用过汇总,但也欢迎使用任何其他方式(gulp、webpack 等)来实现此结果的解决方案。
到目前为止我得到了什么
图书馆
文件结构:
│ package.json
│ rollup.config.js
│ tsconfig.json
│ yarn-error.log
│ yarn.lock
│
└───src
lib.ts
options.ts
package.json
:
{
"name": "library",
"version": "1.0.8",
"description": "example library",
"main": "dist/lib.umd.js",
"module":"dist/lib.esm.js",
"types":"dist/types/lib.d.ts",
"license": "MIT",
"private": true,
"devDependencies": {
"@rollup/plugin-typescript": "^8.3.0",
"rollup": "^2.67.0",
"tslib": "^2.3.1",
"typescript": "^4.5.5"
},
"exports": {
"import": "./dist/lib.esm.js",
"require": "./dist/lib.umd.js"
},
"scripts": {
"build:types": "tsc -d --emitDeclarationOnly",
"build:js": "rollup -c rollup.config.js",
"build:minjs:umd": "terser dist/index.umd.js --compress --mangle > dist/index.umd.min.js",
"build:minjs:esm": "terser dist/index.esm.js --compress --mangle > dist/index.esm.min.js",
"build:minjs": "npm run build:minjs:esm -s && npm run build:minjs:umd -s",
"build": "npm run build:js -s && npm run build:minjs -s && npm run build:types -s",
"prepublishOnly": "npm run lint -s && npm test -s && npm run build",
"semantic-release": "semantic-release"
},
"type":"module"
}
rollup.config.js
:
import typescript from '@rollup/plugin-typescript';
export default {
input: 'src/lib.ts',
output: [
{
file: 'dist/lib.esm.js',
format: 'es',
},
{
file: 'dist/lib.umd.js',
format: 'umd',
name: 'Lib',
},
],
plugins: [typescript({tsconfig:'./tsconfig.json'})],
};
tsconfig.json
:
{
"compilerOptions": {
"target": "es2016",
"module": "esnext",
"moduleResolution": "node",
"declaration": true,
"outDir": "./types",
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
},
}
src/lib.ts
:
import Options from "./options";
export default class Lib{
constructor(options:Options){
console.log("It works!");
console.log(options.message);
}
}
options.ts
:
export default interface Options {
message: string;
}
我正在使用 yarn build:js
.
使用图书馆
有 <script>
个标签
当我将生成的 lib.umd.js
复制到文件夹并创建 index.html
:
<script src=lib.umd.js></script>
<script>
var a = new Lib({message:"message here"});
</script>
有效。到目前为止一切顺利。
在另一个打字稿项目中
接下来,我创建了一个使用我的库的简单打字稿项目。
文件结构:
│ gulpfile.js
│ package.json
│ tsconfig.json
│ yarn.lock
│
├───dist
│ index.html
│
└───Scripts
Index.ts
在 package.json
中,我将我的库作为依赖项,连同 jQuery 以希望排除该项目的不正确配置:
{
"private": true,
"version": "1.0.0",
"scripts": {
"preinstall": "npx use-yarn",
"gulp": "node_modules/.bin/gulp"
},
"name": "ts-import",
"devDependencies": {
"@types/jquery": "^3.5.13",
"gulp": "^4.0.2",
"gulp-browserify": "^0.5.1",
"gulp-clean": "^0.4.0",
"gulp-concat": "^2.6.1",
"gulp-sourcemaps": "^3.0.0",
"gulp-typescript": "^6.0.0-alpha.1",
"gulp-uglify": "^3.0.2",
"typescript": "^4.5.5",
"vinyl-source-stream": "^2.0.0"
},
"dependencies": {
"jquery": "*",
"library": "file:../../library"
}
}
tsconfig.json
:
{
"compilerOptions": {
"noEmitOnError": true,
"noImplicitAny": true,
"sourceMap": true,
"target": "es5",
"moduleResolution": "node",
"outDir":"./js"
},
"compileOnSave": true,
"exclude": [
"**/node_modules/**"
],
"include":[
"./Scripts"
]
}
我正在使用 gulp 编译 ts 和解析导入 - gulpfile.js
:
const gulp = require('gulp');
const {series} = require('gulp');
const clean = require('gulp-clean');
const ts = require('gulp-typescript');
const sourcemaps = require('gulp-sourcemaps');
const browserify = require('gulp-browserify');
const concat = require('gulp-concat');
const uglify = require('gulp-uglify');
function cleanAll(cb) {
return gulp.src([
"./tmp/",
"./dist/js"
], { read: false, allowEmpty: true })
.pipe(clean());
}
function transpileTS() {
const tsproject = ts.createProject('./tsconfig.json');
return tsproject
.src()
.pipe(sourcemaps.init())
.pipe(tsproject()).js
.pipe(sourcemaps.write('./sourcemaps'))
.pipe(gulp.dest('./tmp/js'));
}
function minJS() {
return gulp
.src('./tmp/js/Index.js')
.pipe(sourcemaps.init({ loadMaps: true }))
.pipe(browserify())
// .pipe(uglify())
.pipe(concat('index.min.js'))
.pipe(sourcemaps.write('./sourcemaps'))
.pipe(gulp.dest('./dist/js'))
}
exports.default = series( cleanAll, transpileTS, minJS );
我正在像这样导入和使用我的库 - Scripts/Index.ts
:
import * as $ from "jquery";
import Lib from "library";
$(()=>{
console.log("creating lib instance.");
new Lib({message:"example message here"});
});
但是当我在浏览器中启动它时 - dist/index.html
:
<script src="js/Index.min.js"></script>
我得到一个错误:
Uncaught TypeError: library_1.default is not a constructor
的确,library_1.default
不存在,library_1
确实存在:
> library_1
< class Lib {
constructor(options) {
console.log("It works!");
console.log(options.message);
}
}
我该如何解决这个问题?我怀疑错误是在图书馆的某个地方,但我不知道在哪里。
我已经弄明白了。
在我的 lib.ts
中,我不得不更改导出 class:
import Options from "./options";
class Lib{
constructor(options:Options){
console.log("It works!");
console.log(options.message);
}
}
export default Lib;
接下来,我更改了 rollup.config.js
(添加了 exports:'default'
)以保持导出的 class 全局:
...
{
file: 'dist/lib.umd.js',
format: 'umd',
name: 'Lib',
exports:'default'
},
...
我还必须更改库的 package.json
- 我将 main
指向我的 es 模块,因为它看起来像 browserify 只是忽略了模块指令。
我还最终删除了 exports
部分,因为我们的一些其他项目(不使用 browserify)继续使用 require
文件,而不是 import
文件:
{
"name": "library",
"version": "1.0.16",
"description": "example library",
"main": "dist/lib.esm.js",
"module":"dist/lib.esm.js",
"types":"dist/types/lib.d.ts",
"license": "MIT",
"private": true,
"devDependencies": {
"@rollup/plugin-typescript": "^8.3.0",
"rollup": "^2.67.0",
"tslib": "^2.3.1",
"typescript": "^4.5.5"
},
"exports": {
"import": "./dist/lib.esm.js",
"require": "./dist/lib.umd.js"
},
"scripts": {
"build": "rollup -c rollup.config.js"
}
}
最后,我不得不在我的消费者项目中使用 babelify 来避免 ParseError: 'import' and 'export' may appear only with 'sourceType: module'
而 运行 browserify。
完整的源代码可用here