如何在Stencil.js中使用外部第三方库



我有一个Stencil组件,作为其业务逻辑的一部分,我需要使用外部Javascript文件mylib.js。Javascript文件包含Stencil组件应该使用的一些业务逻辑。

这是我的组件:

import { Component, Element, Prop, h, Host } from '@stencil/core';
import moment from 'moment';
import mylib from 'src/js/mylib.js';
@Component({
tag: 'dashboard-widget',
styleUrl: 'dashboard-widget.css',
shadow: false
})
export class DashboardWidget {
@Element() el: HTMLElement;
@Prop() canvas: HTMLElement;
@Prop() channelName: string = "";
@Prop() channelValue: string = "";
@Prop() isBlinking: boolean = true;
componentDidLoad() {
console.log(mylib.test());
}
render() {
return (
<Host>
<div class="card-content card-content-padding">
<b>{this.channelName}</b>
<h1 class="dashboard-card-value">{this.channelValue}</h1>
<canvas class="dashboard-card-canvas"></canvas>
</div>
</Host>
);
}
}

我一直收到错误

TypeScript找不到模块"src/js/mylib.js"。

我尝试过:

import mylib from 'src/js/mylib.js';
import 'src/js/mylib.js';
import 'mylib' from 'src/js/mylib.js';

但无济于事。

mylib.js文件位于js文件夹中。在线文档根本没有提到如何导入外部库。我成功地导入了moment.js,但这只是因为我首先安装了它:

npm install moment

然后通过以下操作将其导入组件内部:

import moment from 'moment';

我还试图通过在index.html 中引用外部JS库来"导入"它

<script src="assets/js/mylib.js"></script>

该库在组件外部可用,但在内部不可用

既然您提到Moment.js,我将首先解释如何加载它。可以通过在组件模块中导入它来实现这一点,但这会导致大的捆绑包大小,因为目前的npm包不是针对浏览器的,而是用于捆绑包大小无关紧要的Node.js项目。Moment.js在包中分发浏览器捆绑包。因此,您可以在Stencil输出目标中添加一个复制任务,将node_modules/moment/min/moment.min.js复制到构建目录中:

// stencil.config.ts
import { Config } from '@stencil/core';
export const config: Config = {
namespace: 'my-app',
outputTargets: [
{
type: 'www',
copy: [
{
src: '../node_modules/moment/min/moment.min.js',
dest: 'lib/moment.min.js'
}
]
}
]
};

然后,正如您已经尝试使用lib一样,您可以在src/index.html:中加载该脚本

<script src="/lib/moment.min.js"></script>

然而,您的Typescript项目还不知道moment在全局范围内可用。不过,这很容易解决,您只需在项目中的某个地方添加一个声明文件,例如src/global.d.ts,内容为

import _moment from 'moment';
declare global {
const moment: typeof _moment;
}

对于在Node.js上下文而非浏览器上下文中运行的测试文件,您可以导入moment,也可以通过创建内容为的文件(例如jest-setup-file.js(将moment添加到全局范围

global.moment = require('moment');

然后在stencil.config.ts中,只需将setupFilesAfterEnv字段添加到testing:

{
testing: {
setupFilesAfterEnv: ['<rootDir>/jest-setup-file.js']
}
}

如果您在整个应用程序中不需要脚本,但只有在加载特定组件时才需要,那么只从该组件中加载脚本更有意义。最简单的方法是创建一个script元素并将其添加到DOM:

declare const MyLib: any; // assuming that `mylib.js` adds `MyLib` to the global scope
export class MyComp {
componentWillLoad() {
const src = "assets/js/mylib.js";
if (document.querySelector(`script[src="${src}"]`)) {
return; // already exists
}
const script = document.createElement('script');
script.src = src;
document.head.appendChild(script);
}
}

您的脚本/库很可能也会向全局作用域贡献一个变量,因此您必须再次告知Typescript,您可以使用declare关键字来声明全局上下文中存在一个变量(请参阅https://www.typescriptlang.org/docs/handbook/declaration-files/by-example.html#global-变量(。


作为另一个例子,这里有一个我为加载谷歌地图api而编写的助手:

export const importMapsApi = async () =>
new Promise<typeof google.maps>((resolve, reject) => {
if ('google' in window) {
return resolve(google.maps);
}
const script = document.createElement('script');
script.onload = () => resolve(google.maps);
script.onerror = reject;
script.src = `https://maps.googleapis.com/maps/api/js?key=${googleApiKey}&libraries=places`;
document.body.appendChild(script);
});

(google型来自@types/googlemaps封装(

然后我可以像一样使用它

const maps = await importMapsApi();
const service = new maps.DistanceMatrixService();

要导入NPM未安装的文件,可以使用前缀为./../:的相对路径

import mylib from '../../js/mylib.js';

您可以导入从JS文件导出的所有内容,甚至可以使用命名导入:

mylib.js

export function someFunction() {
// some logic
}

仪表板小部件.tsx

import { someFunction } from '../../js/mylib.js`;
const result = someFunction();

最新更新