Как использовать импортированные сценарии, требующие DOM и окна, в Javascript / Node.js Azure Function - PullRequest
0 голосов
/ 25 июня 2019

Я пытаюсь использовать внешний JavaScript в функции Azure (вариант javascript / node.js). Поскольку внешний javascript (мне нужно использовать kendo) зависит от DOM и окна, я попытался использовать JSDOM (но мне не нужно использовать JSDOM, если есть какая-то лучшая / более простая альтернатива).

Это упрощенный пример того, что у меня есть:

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    var html = '<!DOCTYPE html>'
    + '<html>'
    +   '<head>'
    +       '<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>'
    +       '<script src="https://kendo.cdn.telerik.com/2019.2.514/js/kendo.all.min.js"></script>'
    +   '</head>'
    +   '<body>'
    +       '<script>'
    +           'var myDiv = document.createElement("div");'        
    +           'myDiv.innerHTML = "Hello World";'
    +           'document.body.appendChild(myDiv);'
    +       '</script>'
    +   '</body>'
    + '</html>'
    ;

    var jsdom = require('jsdom');
    const { JSDOM } = jsdom;

    const dom = new JSDOM(html, {
        runScripts: "dangerously",
        resources: "usable"
    });

    var test = dom.serialize();
    context.log(test);

    context.res = {
        body: test
    };
};

При запуске этой функции Azure она должна включать jquery и kendo и создавать div, содержащий «Hello World». Это не работает, хотя.

Сценарий, создающий div Hello World, выполняется только в том случае, если я закомментирую либо

+       '<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>'
+       '<script src="https://kendo.cdn.telerik.com/2019.2.514/js/kendo.all.min.js"></script>'

или

resources: "usable"

но тогда я не могу использовать jquery и кендо.

В соответствии с этой документацией jsdom параметр resources: "usable" должен помочь, но по какой-то причине он не работает.

Я использую "jsdom": "^ 15.1.1"

UPDATE : Я попытался обойти, добавив сценарии, как это:

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    var html = '<!DOCTYPE html>'
    + '<html>'
    +   '<head>'
    +   '</head>'
    +   '<body>'
    +       '<script>'
    +           'var myDiv = document.createElement("div");'        
    +           'myDiv.innerHTML = "Hello World";'
    +           'document.body.appendChild(myDiv);'
    +           'var scriptTag = document.createElement("script");'        
    +           'scriptTag.innerHTML = window.jqueryString;'
    +           'document.head.appendChild(scriptTag);'
    +       '</script>'
    +   '</body>'
    + '</html>'
    ;

    var jsdom = require('jsdom');
    const { JSDOM } = jsdom;

    var fs = require("fs");
    global.jqueryString = fs.readFileSync(__dirname + '//jquery.js').toString();
    //context.log(jqueryString);

    const dom = new JSDOM(html, {
        runScripts: "dangerously"
    });

    var test = dom.serialize();
    context.log(test);


    context.res = {
        body: test
    };
};

Это добавление тега скрипта в заголовок, но innerHTML имеет значение "undefined" вместо jqueryString. Вне JSDOM (см. Закомментированную строку) ведение журнала jqueryString отображает содержимое jquery.js, как и ожидалось. Но внутри JSDOM эта переменная кажется недоступной. Как я могу передать jqueryString в JSDOM?

Ответы [ 2 ]

1 голос
/ 28 июня 2019

Я тщательно осмотрел пакет узла jsdom, затем обнаружил, что для функции Loading subresources требуется браузер без головы, такой как Chrome без головы, через karma. Однако из-за Win32k.sys (User32/GDI32) Restrictions из Azure Web App sandbox он никогда не будет работать нормально, как вы хотите, в службе приложений Azure для Windows, поскольку браузер без монитора требует поддержки GDI.

enter image description here

Поэтому я рекомендовал вам перенести вашу функцию в Azure Functions для Linux (она основана на Docker Container), перекомпилировав ее в Azure Functions Core Tools в качестве официального документа Create your first function hosted on Linux using Core Tools and the Azure CLI (preview) сказал. Или вы должны использовать Windows, Azure Windows VM будет вашим лучшим выбором.

Надеюсь, это поможет.

0 голосов
/ 01 июля 2019

С помощью @PeterPan мне удалось решить мою проблему, используя основанную на Docker функцию Azure с Кукольник .

Функция FunctionApp на основе Init Docker:

func init MyFunctionProj --docker (выберите -> узел -> javascript)

Отредактируйте MyFunctionProj \ Dockerfile для использования estruyf / azure-function-node-puppeteer и fs:

FROM estruyf/azure-function-node-puppeteer
RUN npm i fs
COPY . /home/site/wwwroot

Добавить fs к зависимостям в MyFunctionProj \ package.json:

"dependencies": {
    "fs": "0.0.1-security"
  }

Создать функцию HttpTrigger:

cd MyFunctionProj
func new --name MyHttpTrigger --template "HttpTrigger"

Предоставить доступ к функции:

Установить "authLevel": "anonymous" в MyFunctionProj \ MyHttpTrigger \ function.json (причину см. здесь .)

Создать файл MyFunctionProj \ MyHttpTrigger \ content.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"/>
    <title>ContentHtml</title>

    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="https://kendo.cdn.telerik.com/2019.2.514/js/kendo.all.min.js"></script>
</head>
<body>

<script>
    $(document).ready(function() {
       var myComputationResult = .... // use included scripts to perform computation
       $("#resultData").html(JSON.stringify(myComputationResult));
    });
</script>
<div id="resultData"></div>
</body>
</html>

Редактирование логики функций в MyFunctionProj \ MyHttpTrigger \ index.js (на основе this ):

const puppeteer = require('puppeteer');
const fs = require("fs");

module.exports = async (context, req) => {    
    const browser = await puppeteer.launch({
        args: [
            '--no-sandbox',
            '--disable-setuid-sandbox'
        ]
    });

    var contentHtml = fs.readFileSync(__dirname + '//content.html', 'utf8');

    const page = await browser.newPage();
    await page.goto(`data:text/html,${contentHtml}`, { waitUntil: 'networkidle2' });
    const resultData = await page.evaluate(() => document.querySelector('#resultData').innerHTML);
    await browser.close();

    context.res = {
        // status: 200, /* Defaults to 200 */
        body: `Result: ${resultData}`
    };
};

Сборка образа докера:

docker build --tag <docker-id>/mydockerimage:v1.0.0 .

Запустить образ докера:

docker run -p 8080:80 -it <docker-ID>/mydockerimage:v1.0.0

Проверка локального изображения функции в браузере:

http://localhost:8080/api/MyHttpTrigger

Загрузка изображения в Docker Hub:

docker login --username <docker-id>
docker push <docker-id>/mydockerimage:v1.0.0

Создайте новую функцию Azure онлайн и используйте изображение из Docker Hub, как описано здесь .

...