使用模块系统从 HTML 调用打字稿函数
Calling typescript function from HTML using a module system
我想从 HTML 调用 TypeScript(最终 JavaScript)函数。问题是我还想使用模块系统(systemjs、commonjs 等)和 webpack。
这是一个例子:
example.ts:
export class Example {
myFunction() {
alert('Test');
}
}
example2.ts:
export function doSomething() {
alert('Test2');
}
example.html:
<html>
<head>
<script src="path/to/the/compiled/js/file.js"></script>
<script>
$(document).ready(function() {
$('#test-btn').click(function(){
var example = new Example(); //error1
example.myFunction();
});
});
</script>
</head>
<body>
<button id="test-btn">Click me</button>
<a href="javascript:doSomething()">Click me too</a> <!-- error2 -->
</body>
</html>
错误注释指出错误发生的位置:找不到导出的 class/function,因为使用了模块系统。如果我查看已编译的 js 文件,我可以看到 class 和函数声明放在某些模块函数中,因此无法从 HTML.
访问它们
目前我正在通过将整个 $(document).ready...
部分移动到 TypeScript 文件中来使用变通方法。但是对于 <a href...
示例,我没有任何解决方法。
所以我的最后一个问题:是否真的可以从 HTML 调用 TypeScript function/class 并使用模块系统?
是的。 webpack 有两种支持方式
1) 使用library 选项输出。这会将入口文件的导出写入您选择的全局范围内的命名空间变量
myEntryFile.ts
import {Example} from './example'
import {doSomething} from './example2'
export {
Example,
doSomething
}
webpack.config.js
output: {
//... your normal output config her
library: 'MyExposedNamespace'
}
现在可以在 window.MyExposedNamespace
window.MyExposedNamespace.doSomething()
const myExample = new window.MyExposedNamespace.Example()
对于更高级的用法,您还可以通过 libraryTarget 更改命名空间应用的范围,这样就不会污染全局范围
2) 使用 expose-loader
webpack.config.js
module: {
rules: [
{ test: /example\.ts$/,
use: [
{ loader: 'expose-loader', options: 'Example'},
'awesome-typescript-loader' // must transpile as file is typescript
]
},
{ test: /example2\.ts$/,
use: [
{ loader: 'expose-loader', options: 'doSomeThing'},
'awesome-typescript-loader'
]
}
]
}
你还必须记得将这些文件导入你项目的某处,否则webpack会忽略它们。你不必实际使用它们,它只是为了让 webpack 跟踪依赖关系。最合乎逻辑的地方是你的入口文件
myEntryFile.ts
import './example'
import './example2'
然后可以通过全局范围调用它们(在浏览器中这当然是 window
)
window.doSomeThing()
const myExample = new window.Example()
由于在公开之前还需要进行打字稿转译步骤,这可能会变得更加棘手,这取决于您的其他配置,可能比上面的简单版本更复杂
因此我建议第一个解决方案是最简单的
我想从 HTML 调用 TypeScript(最终 JavaScript)函数。问题是我还想使用模块系统(systemjs、commonjs 等)和 webpack。
这是一个例子:
example.ts:
export class Example {
myFunction() {
alert('Test');
}
}
example2.ts:
export function doSomething() {
alert('Test2');
}
example.html:
<html>
<head>
<script src="path/to/the/compiled/js/file.js"></script>
<script>
$(document).ready(function() {
$('#test-btn').click(function(){
var example = new Example(); //error1
example.myFunction();
});
});
</script>
</head>
<body>
<button id="test-btn">Click me</button>
<a href="javascript:doSomething()">Click me too</a> <!-- error2 -->
</body>
</html>
错误注释指出错误发生的位置:找不到导出的 class/function,因为使用了模块系统。如果我查看已编译的 js 文件,我可以看到 class 和函数声明放在某些模块函数中,因此无法从 HTML.
访问它们目前我正在通过将整个 $(document).ready...
部分移动到 TypeScript 文件中来使用变通方法。但是对于 <a href...
示例,我没有任何解决方法。
所以我的最后一个问题:是否真的可以从 HTML 调用 TypeScript function/class 并使用模块系统?
是的。 webpack 有两种支持方式
1) 使用library 选项输出。这会将入口文件的导出写入您选择的全局范围内的命名空间变量
myEntryFile.ts
import {Example} from './example'
import {doSomething} from './example2'
export {
Example,
doSomething
}
webpack.config.js
output: {
//... your normal output config her
library: 'MyExposedNamespace'
}
现在可以在 window.MyExposedNamespace
window.MyExposedNamespace.doSomething()
const myExample = new window.MyExposedNamespace.Example()
对于更高级的用法,您还可以通过 libraryTarget 更改命名空间应用的范围,这样就不会污染全局范围
2) 使用 expose-loader
webpack.config.js
module: {
rules: [
{ test: /example\.ts$/,
use: [
{ loader: 'expose-loader', options: 'Example'},
'awesome-typescript-loader' // must transpile as file is typescript
]
},
{ test: /example2\.ts$/,
use: [
{ loader: 'expose-loader', options: 'doSomeThing'},
'awesome-typescript-loader'
]
}
]
}
你还必须记得将这些文件导入你项目的某处,否则webpack会忽略它们。你不必实际使用它们,它只是为了让 webpack 跟踪依赖关系。最合乎逻辑的地方是你的入口文件
myEntryFile.ts
import './example'
import './example2'
然后可以通过全局范围调用它们(在浏览器中这当然是 window
)
window.doSomeThing()
const myExample = new window.Example()
由于在公开之前还需要进行打字稿转译步骤,这可能会变得更加棘手,这取决于您的其他配置,可能比上面的简单版本更复杂
因此我建议第一个解决方案是最简单的