﻿# Серверные зависимости пакетов npm

> [HTML Version](npm-package.html)

В ELMA365 On-Premises вы можете подключать серверные зависимости в скриптах виджетов и пользовательских модулей. Это позволит решить ряд специфичных задач при разработке без написания своего микросервиса. Для этого используйте экосистему npm-пакетов при разработке серверных скриптов. Например, можно использовать пакет [XLSX](https://www.npmjs.com/package/xlsx) для чтения данных из excel-файла с помощью команд:

````
import \* as XLSX from 'xlsx';  
  
const url = await Context.data.file.getDownloadUrl();  
const req = await fetch(url);  
const data = await req.arrayBuffer();  
  
const workbook = XLSX.read(data);  
const sheets = workbook.Sheets;  
const cellValue = sheets\['List1'\]\['A1'\].v;  


начало внимание

````
Подключение серверных зависимостей пакетов npm доступно только в [ELMA365 On-Premises](elma365-on-premises.md).

````
конец внимание

````
Чтобы собрать npm-пакет с зависимостями, упакуйте готовую папку **node\_modules **и файл **package.json **в архив с названием **dependencies.tar.gz**. Подробнее о том, как это сделать, читайте ниже:

- [сборка пакета с помощью Shell-скрипта для Linux, macOS](#npm-package-shell-linuxmacos);

- [сборка пакета с помощью PowerShell-скрипта для Windows](#npm-package-powershell-windows).

**Важно**: перед сборкой пакетов с серверными зависимостями установите и запустите Docker.

## Сборка пакета с серверными зависимостями с помощью Shell-скрипта для Linux, macOS

1. Создайте пустую папку на своём компьютере. Скопируйте приведённый ниже скрипт и сохраните его как файл с названием **makedeps.sh** в созданной папке:

````
rm -rf ./deps  
docker run -v \`pwd\`:/data -w /data/deps --platform linux/amd64 --rm node:14.16.0-alpine /bin/sh -c "npm init -y \&\& npm i \$\*"  
docker run -v \`pwd\`:/data -w /data --platform linux/amd64 --rm busybox tar -zcf dependencies.tar.gz -C /data/deps node\_modules package.json  
rm -rf ./deps

2. ````
Через консоль разработчика найдите сохранённый файл и сделайте его исполняемым:

````
\$chmod 755 makedeps.sh

3. ````
Запустите скрипт, передав в качестве параметров список npm-пакетов. Например, для пакета XLSX: 

````
\$./makedeps.sh xlsx semver

````
В результате выполнения команды сформируется архив с зависимостями **dependencies.tar.gz**.

4. Загрузите пакет в систему. Это можно сделать в [настройках виджета](client_server_scripts.md) в дизайнере интерфейсов и в пользовательском модуле при создании [метода API](extention-api.md) или [обработчика событий](events_processing.md) с типом **Запуск скрипта**: добавьте полученный архив с зависимостями на вкладке **Файлы**.

Упакованные серверные зависимости можно использовать в коде серверного скрипта.

## Сборка пакета с серверными зависимостями с помощью PowerShell-скрипта для Windows

1. Создайте пустую папку на своём компьютере. Скопируйте приведённый ниже скрипт и сохраните его как файл с названием **makedeps.ps1** в созданной папке:

````
\$ErrorActionPreference = "SilentlyContinue" #This will hide errors  
Remove-Item -Recurse -Force .\\deps  
\$ErrorActionPreference = "Continue" #Turning errors back on  
docker run -v \$\{PWD\}:/data -w /data/deps --platform linux/amd64 --rm node:14.16.0-alpine /bin/sh -c "npm init -y \&\& npm i \$args"  
docker run -v \$\{PWD\}:/data -w /data --platform linux/amd64 --rm busybox:stable tar -zcf dependencies.tar.gz -C /data/deps node\_modules package.json  
Remove-Item -Recurse -Force .\\deps

2. ````
Запустите скрипт, передав в качестве параметров список npm-пакетов. Например, для пакета XLSX: 

````
\$./makedeps.ps1 xlsx semver

````
В результате выполнения команды сформируется архив с зависимостями **dependencies.tar.gz**.

3. Загрузите пакет в систему. Это можно сделать в [настройках виджета](client_server_scripts.md) в дизайнере интерфейсов и в пользовательском модуле при создании [метода API](extention-api.md) или [обработчика событий](events_processing.md) с типом **Запуск скрипта**: добавьте полученный архив с зависимостями на вкладке **Файлы**.

Упакованные серверные зависимости можно использовать в коде серверного скрипта.

## Особенности подключения модулей

Обратите внимание на особенности импорта компонентов при подключении модулей.

| | |
|------|------|
| **В пользовательских скриптах** | 
| можно импортировать: | нельзя импортировать: |
| - модули из **package.json** (раздел dependencies). | - транзитивные зависимости;<br>- модули хоста (по отношению к [worker](https://nodejs.org/docs/latest-v14.x/api/cluster.html#cluster_class_worker));<br>- встроенные модули **node.js** (fs, path, tty и т. д.). |
| **Внутри внешних модулей импортируемых в скрипте** | 
| можно импортировать: | нельзя импортировать: |
| - любые другие модули, присутствующие в директории с зависимостями;<br>- встроенные модули **node.js** (fs, path, tty и т. д.). | - модули хоста (по отношению к [worker](https://nodejs.org/docs/latest-v14.x/api/cluster.html#cluster_class_worker)). |


Компиляция TypeScript на сервере выполняется со следующими параметрами **tsconfig**:

````
\{  
    allowJs: true,  
    checkJs: false,  
    declaration: false,  
    module: "commonjs",  
    moduleResolution: "node",  
    noImplicitAny: true,  
    strictNullChecks: true,  
    stripInternal: true,  
    skipDefaultLibCheck: true,  
    target: "ES2017",  
    typeRoots: \['node\_modules/@types', 'node\_modules'\],  
    lib: \['es2016'\]  
\}

````
Обратите внимание, не все npm-пакеты работают с такими параметрами без изменений. Возможно, вам понадобится обернуть их в тонкую прослойку, совместимую с CommonJS или AMD.

## Поддерживаемые модульные системы JavaScript

В качестве серверных зависимостей вы можете использовать модули на основе двух модульных систем JavaScript: CommonJS и UMD (Universal Module Definition).

### Примеры импорта модуля

На примере модуля CommonJS рассмотрим, как его импортировать.

Допустим, модуль содержит одну функцию и одну константу:

````
function add(a, b) \{  
 return a + b;  
\}  
  
const name = 'noname'  
  
module.exports = \{  
 add,  
 name  
\}

````
Такой модуль можно импортировать тремя способами:

````
// 1 named import  
  
import \{ add, name \} from 'module\_name';  
  
async function test(): Promise<void> \{  
   Context.data.res = add(1, 3);  
   Context.data.text = name;  
\}  
  
// 2 namespace import  
  
import \* as m from 'module\_name';  
  
async function test(): Promise<void> \{  
   Context.data.res = m.add(1, 3);  
   Context.data.text = m.name;  
\}  
  
// 3 alias import  
  
import \{ add as plus \} from 'module\_name';  
  
async function test(): Promise<void> \{  
   Context.data.res = plus(1, 3);  
\}

````
Часто документация к модулям содержит примеры, которые используют импорт с помощью \[OBJECT\]. Вместо него вы можете применить \[OBJECT\], как во втором примере выше:

````
var m = require('module\_name');  
m.example();  
  
...  
  
import \* as m from 'module\_name';  
m.example();  


````
