Eksperymentowałem z nową wersją native ECMAScript module support, która została ostatnio dodana do przeglądarek. Przyjemnie jest móc importować skrypty bezpośrednio i czysto z JavaScript.Inlineing ECMAScript Modules w HTML
/example.html
<script type="module">
import {example} from '/example.js';
example();
</script>
/example.js
export function example() {
document.body.appendChild(document.createTextNode("hello"));
};
Jednak to tylko pozwala mi na importowanie modułów, które są zdefiniowane przez osobne zewnętrznych plików JavaScript. Zazwyczaj wolę wstawiać niektóre skrypty używane do wstępnego renderowania, więc ich żądania nie blokują reszty strony. Z tradycyjnej biblioteki nieformalnie zbudowane, że może wyglądać następująco:
/inline-traditional.html
<body>
<script>
var example = {};
example.example = function() {
document.body.appendChild(document.createTextNode("hello"));
};
</script>
<script>
example.example();
</script>
Jednak naiwnie inline moduły plików oczywiście nie będzie działać, ponieważ spowodowałoby to usunięcie pliku używany do identyfikacji modułu do innych modułów . Prasowanie HTTP/2 może być kanonicznym sposobem radzenia sobie z tą sytuacją, ale nadal nie jest to opcja we wszystkich środowiskach.
Czy można przeprowadzić równoważną transformację za pomocą modułów ECMAScript? Czy jest jakiś sposób, aby <script type="module">
zaimportować moduł wyeksportowany przez inny w tym samym dokumencie?
sobie wyobrazić, to może pracować przez umożliwienie skrypt, aby określić ścieżkę do pliku, i zachowywać się tak, jakby to był już pobrane lub popychany ze ścieżki.
/inline-name.html
<script type="module" name="/example.js">
export function example() {
document.body.appendChild(document.createTextNode("hello"));
};
</script>
<script type="module">
import {example} from '/example.js';
example();
</script>
Albo o zupełnie innym systemem odniesienia, takie jak stosuje się do lokalnych odn SVG:
/inline-id.html
<script type="module" id="example">
export function example() {
document.body.appendChild(document.createTextNode("hello"));
};
</script>
<script type="module">
import {example} from '#example';
example();
</script>
ale żaden z tych hypotheticals faktycznie pracują, a ja Haven” t widział alternatywę, która ma.
Być może jest lepszy sposób, aby to osiągnąć - potencjalnie korzystając z Service Workers? –
Nie sądzę, aby "moduł inline" zgodny z homebrew, nie spełniający specyfikacji, mógł być uważany za dobry początek w przypadku modułów ES. Pakiety Webpack/Rollup są nadal niezbędne w produkcji - * zwłaszcza * jeśli nie chcesz blokować żądań. Tak, pracownik serwisu wygląda jak realne rozwiązanie - ale nadal powinien wysyłać żądania w celu dostarczenia danych ... które mogą być blokowane, przy okazji. – estus
@estus Wyobrażałam sobie, używając pracowników serwisu do wstawiania znaczników '
Hacking Wraz naszych własnych
import from '#id'
Eksport/import między skryptami inline nie są natywnie obsługiwane, ale to była zabawa ćwiczenie włamać razem implementację dla moich dokumentów.Code-golfed dół do małego bloku, używam go tak:
Zamiast
<script type="module">
, musimy określić nasze elementy skryptu przy użyciu niestandardowego typu jak<script type="inline-module">
. Zapobiega to próbie wykonania przez przeglądarkę własnej zawartości, pozostawiając je do obsługi. Skrypt (pełna wersja poniżej) wyszukuje wszystkie elementy skryptuinline-module
w dokumencie i przekształca je w elementy klasycznego modułu skryptów zgodnie z naszym zachowaniem.Skrypty wbudowane nie mogą być bezpośrednio importowane od siebie, więc musimy nadać skrypty importowalnym adresom URL. Generujemy adres URL
blob:
dla każdego z nich, zawierający ich kod i ustawiając atrybutsrc
, aby uruchamiał się z tego adresu URL, zamiast uruchamiać wbudowane. Adresy URLblob:
działają jak normalne adresy URL z serwera, dzięki czemu można je importować z innych modułów. Za każdym razem, gdy widzimy kolejnyinline-module
próbujący importować z'#example'
, gdzieexample
jest identyfikatoreminline-module
, który zmieniliśmy, modyfikujemy ten import, aby zaimportować go z adresu URLblob:
. Utrzymuje to jednorazową realizację i deduplikację odwołań, które powinny mieć moduły.Wykonanie elementów skryptowych modułu jest zawsze odroczony aż po dokument jest analizowany, więc nie musimy się martwić o starają się wspierać sposób, że tradycyjne elementy skrypt może zmodyfikować dokument, podczas gdy jest wciąż analizowana .
Ostrzeżenia: to prosta implementacja nie obsługuje skryptów elementy dodane po początkowym dokument został przeanalizowany ani dopuszczać, elementy skryptowe importować z innych elementów skryptowych, które występują po nich w dokumencie. Jeśli masz w dokumencie zarówno elementy skryptowe
module
, jak iinline-module
, ich względna kolejność wykonania może być niepoprawna. Transformacja kodu źródłowego jest przeprowadzana za pomocą prostego wyrażenia regularnego, które nie obsługuje niektórych przypadków brzegowych, takich jak okresy w identyfikatorach.Źródło
2017-05-07 16:44:22
Możesz dalej grać w regex w '/ (z | import) \ s + ('|") (# [\ w \ -] +) \ 2/g' – Bergi
Jest to możliwe w przypadku pracowników serwisowych.
Ponieważ pracownik serwisowy powinien zostać zainstalowany, zanim będzie mógł przetworzyć stronę, wymaga to oddzielnej strony, aby zainicjować pracownika, aby uniknąć problemu z kurczakiem/jajkiem - lub strona może zostać ponownie załadowana, gdy pracownik jest gotowy.
Here's an example który ma być wykonalne w przeglądarkach obsługujących rodzime ES modułów i
async..await
(czyli Chrome)index.html
sw.js
Ciała skryptów są buforowane (nat ive
Cache
może być również używany) i zwracane dla odpowiednich żądań modułów.Zmartwienia
Podejście jest gorsza aplikacji zbudowanej i pakietowego z łączenie narzędzie jak Webpack lub pakiet pod względem wydajności, elastyczności, solidności i wsparcia przeglądarki - zwłaszcza jeśli blokowanie jednoczesnych żądań są podstawowym problemem .
Skrypty śródlinowe zwiększają wykorzystanie przepustowości, w naturalny sposób unika się tego, gdy skrypty są ładowane raz i buforowane przez przeglądarkę.
Skrypty śródliniowe nie są modułowe i są sprzeczne z koncepcją modułów ES (chyba że są generowane z rzeczywistych modułów po szablonie po stronie serwera).
Inicjalizacja pracownika serwisowego powinna zostać przeprowadzona na oddzielnej stronie, aby uniknąć niepotrzebnych żądań.
Rozwiązanie jest ograniczone do jednej strony i nie uwzględnia
<base>
.Wyrażenie regularne służy tylko do celów demonstracyjnych. W przypadku użycia jak w powyższym przykładzie umożliwia wykonanie dowolnego kodu JS, który jest dostępny na stronie. Należy użyć sprawdzonej biblioteki, takiej jak
parse5
(spowoduje to zwiększenie wydajności, a mimo to mogą pojawić się obawy o bezpieczeństwo). Nigdy nie używaj wyrażeń regularnych do parsowania DOM.Źródło
2017-09-07 01:31:25 estus
Uwielbiam to! Bardzo sprytnie. –
To byłoby nawet bardziej obrzydliwe, więc pewnie go nie polecam, ale jeśli przepisujemy index.html, to daje nam to sposób na synchroniczne wykrywanie, czy pracownik serwisu został załadowany, poprzez dodanie do strony jakiegoś atrybutu, a więc cokolwiek innego z ładowania/uruchamiania niepoprawnie za pierwszym razem, zamiast czekać na wynik async getRegistration –
Tak. 'location.reload()' nie pachnie dobrze, ale demonstruje problem.Zalecam generalnie, aby mieć oddzielne odpowiedzi serwera dla punkty wejściowe '/' i '/? serviceWorkerInstalledOrNotSupported'. – estus