Я пишу некоторые пользовательские элементы HTML5, которые содержат код, который транспилируется, чтобы он мог фактически работать на странице (графический код, латекс и т. д.), но я не могу найти какую-либо страницу или вопрос Stackoverlow, который объясняет, и как загрузить скрипт так, чтобы он ограничивался самим настраиваемым элементом.
Вместо этого все, что я могу найти, это полное отсутствие информации, поэтому я использую довольно глупую вставку ее в заголовок документа, переписанную так, чтобы она сначала брала правильный элемент из глобального реестра, что очень грязно. I работает, но было бы намного лучше иметь возможность внедрять сценарии в теневой DOM таким образом, чтобы они выполнялись, точно зная, для какого элемента они выполняются.
Прямо сейчас код (в сокращенном виде) выглядит так:
import { uuid } from "./uuid.js";
import { Parser } from "./code-parser.js";
class MyElement extends HTMLElement {
constructor() {
super();
this.uid = uuid.v4();
window[this.uid] = this;
const jsCode = `
import { Base, API, ... } from "./lib.js";
class Example extends Base {
constructor() {
super(window[${this.uid}]);
delete window[${this.uid}];
}
${Parser.rewrite(this.textContent)}
}
new Example();
`;
const script = document.createElement(`script`);
script.type = `module`;
script.src = URL.createObjectURL(
new Blob([jsCode], {type: `text/javascript`})
);
this.attachShadow({ mode: 'open' }).append(script);
}
}
customElements.define(`my-element`, MyElement);
export { MyElement }
Это работает, конечно, но работает (временно) загрязняя window
. Есть ли способ прикрепить элемент сценария к пользовательскому элементу или теневой DOM пользовательского элемента, чтобы он выполнялся со знанием того, для какого пользовательского элемента или какой теневой DOM он выполняется?
Изменить: чтобы быть явным, это должно работать для сценариев, использующих современный код, основанный на модули: любой оператор import
все еще нуждается в разрешении. Также обратите внимание, что все, что основано на подходах, требующихunsafe-eval
(6.1 .11.3) или unsafe-inline
для добавления в CSP script-src
использовать нельзя.
import
, вы можете очень хорошо преобразовать их в динамические вызовыimport()
и выполнить все из конструктора, очень нормально и очень чисто. - person Kaiido   schedule 01.08.2020new Function()
. Что-то вродеconst AsyncFunction = Object.getPrototypeOf(async function(){}).constructor; new AsyncFunction(`const API = await import("./api.js"); const Base= await import("./base.js"); ...
- person Kaiido   schedule 02.08.2020unsafe-eval
) запрещаетeval()
,new Function()
и малоизвестные формы исполнения строкsetTimeout
иsetInterval
. Этот элемент предназначен для работы на произвольных сайтах, поэтому он должен по-прежнему работать на сайтах с обычным CSP. Необходимостьunsafe-inline
прямо сейчас уже довольно сомнительна, и мне, вероятно, придется вместо этого переключиться на инъекциюsrc="blob:..."
. Независимо от этого, первоначальный вопрос остается в силе: как скрипт, внедренный в теневой DOM, может получить ссылку на этот теневой DOM или на владельца теневого DOM? - person Mike 'Pomax' Kamermans   schedule 02.08.2020unsafe-inline
иunsafe-eval
не обсуждаются, а код обновлен для использования вместо этого внедрения больших двоичных объектов. - person Mike 'Pomax' Kamermans   schedule 02.08.2020script-url: 'self'
. Я думаю, вам нужно немного реорганизовать свой проект. На ум приходят несколько решений (все менее привлекательных, чем другие): 1) Определите свой собственный язык, разберите его из содержимого «кода программы» и выполните его на своем собственном движке. 2) Создайте нединамический инструмент предварительной сборки, который ваши пользователи должны будут вызывать для создания встроенного файла. 3) заставить использовать unsafe-eval. (Я думаю, что 1 и 2 на самом деле то, что делают подобные проекты, такие как реакция). - person Kaiido   schedule 04.08.2020self
, это также белые списки протоколов и доменов, аblob:
как часть CSP не так уж и редкость, тогда как никто в здравом уме не добавитunsafe-eval
в свой список CSP. Что касается предложения 3, очевидно, что оно не выполняется, и хотя 1 и 2 возможны, оба они имеют недостатки, которые гораздо серьезнее, чем работающее в настоящее время решение, основанное на временном глобальном загрязнении. Похоже, вы уверены, что скрипт никогда не сможет узнать, в каком теневом DOM он находится: с мотивацией, основанной на спецификациях, это было бы хорошим ответом. - person Mike 'Pomax' Kamermans   schedule 04.08.2020type="module"
, вставленные в теневой DOM, могут найти свой теневой корень ? Потому что я нигде не могу найти ничего, что объясняло бы, как это могло произойти. Если вы знаете (или если вы знаете, что это явно невозможно), то ответ, который я могу пометить как принятый, будет оценен. Альтернативные подходы не обсуждаются: этот вопрос явно и только касается скрипта, внедренного в теневой DOM. - person Mike 'Pomax' Kamermans   schedule 05.08.2020<SCRIPT>
в shadowDOW не ограничен до shadowDOM. Он выполняется в глобальной области видимости. - person Danny '365CSI' Engelman   schedule 08.08.2020