Как использовать внешнюю стороннюю библиотеку в Stencil. js - PullRequest
0 голосов
/ 11 марта 2020

У меня есть компонент Stencil, и, как часть его бизнес-логики c, мне нужно использовать внешний Javascript файл mylib.js. Файл Javascript содержит некоторые бизнес-логики c, которые должен использовать компонент 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';

безрезультатно.

The * Файл 1018 * находится в папке js. В онлайн-документации вообще не упоминается, как импортировать внешние библиотеки. Я успешно импортировал момент. js, но только потому, что сначала установил его, выполнив:

npm install moment

, а затем импортировал его внутри компонента, выполнив:

import moment from 'moment';

I также пытался «импортировать» внешнюю библиотеку JS, ссылаясь на нее внутри индекса. html

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

Библиотека доступна вне компонента, но не внутри него

Ответы [ 2 ]

2 голосов
/ 11 марта 2020

Поскольку вы упоминаете Moment. js, я сначала объясню, как его загрузить. Это можно сделать так, как вы это сделали, импортировав его в модуль вашего компонента, однако это приведет к большому размеру пакета, поскольку моментальный пакет npm предназначен не для браузеров, а для использования в проектах Node.js, где размер пакета не имеет значения Момент. 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'
        }
      ]
    }
  ]
};

Затем, как вы уже пробовали с вашей библиотекой, вы можете загрузить этот скрипт в 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) с содержимым

global.moment = require('moment');

, а затем в stencil.config.ts вы просто добавьте поле setupFilesAfterEnv к testing:

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

Если вам не нужен скрипт во всем приложении, а только при загрузке указанного c компонента, он делает больше смысла загружать скрипт только из этого компонента. Самый простой способ сделать это - создать элемент 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 -variables ).


В качестве другого примера, вот помощник, который я написал для загрузки API карт Google:

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();
1 голос
/ 12 марта 2020

Для импорта файлов, которые не установлены NPM, вы можете использовать относительные пути с префиксом ./ или ../:

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

Вы можете импортировать все, что экспортируется из этого JS файл и даже использование именованных импортов:

mylib. js

export function someFunction() {
  // some logic
}

dashboard-widget.tsx

import { someFunction } from '../../js/mylib.js`;

const result = someFunction();
...