Jak wykorzystać Angular do tworzenia rozszerzeń do Google Chrome
Jakiś czas temu dostałem za zadanie stworzyć rozszerzenie do Chrome. Jako fan Angulara chciałem wykorzystać właśnie ten framework. Niestety już na samym początku natrafiłem na kilka problemów, których rozwiązanie zajęło mi sporo czasu. Dziś chcę podzielić się z Wami wiedzą zdobytą podczas całego procesu, abyście sami nie musieli już odnajdywać tego, co było mi wtedy potrzebne :)
Teoria
Jeżeli ktoś nie tworzył nigdy rozszerzenia do Chrome, może zastanawiać się nad sensownością poruszania tego tematu. Ja sam przygotowując się do wykonania swojego zadania, natrafiłem na masę artykułów sugerujących, że proces ten wymaga jedynie podstawowej wiedzy na temat technologii webowych…
… i teoretycznie teksty te mówiły prawdę. Rozszerzenie jest jedynie odpowiednio spreparowaną aplikacją webową. W praktyce jednak problem pojawia się przy odpowiednim przygotowywaniu naszego kodu.
Główna różnica polega na tym, że rozszerzenie składa się z czterech mniejszych elementów, które wykonują niezależnie różne zadania. Jest to związane z przeznaczeniem takiej aplikacji i bezpieczeństwem użytkownika. Te elementy to kolejno:
Popup
To główna część naszej aplikacji, która uruchamia się po naciśnięciu ikony rozszerzenia. To centrum dowodzenia, w którym użytkownik zobaczy interfejs ze wszystkimi dostępnymi opcjami, które dla niego przygotujemy. Możemy dowolnie go zmieniać w zależności od naszych potrzeb. Cały kod JavaScript działa jedynie, gdy użytkownik ma powiększone okienko z naszym popupem.
Background
Jest to kod JavaScript, który działa cały czas w tle naszej aplikacji, dzięki czemu nie resetuje się, gdy użytkownik przechodzi między różnymi kartami. W przeciwieństwie do popupu, nie przestaje działać nawet po zamknięciu okna z naszym rozszerzeniem.
Content Script
To plik z kodem JavaScript, który można dodać do podstrony. Ma on pewne ograniczenia, które utrudniają wykradanie danych użytkownika. Warto pamiętać o tych ograniczeniach i mieć je na uwadze.
Options
Działa podobnie jak popup, z tą jednak różnicą, że jego jedynym zadaniem powinno być przeniesienie użytkownika do fragmentu aplikacji z ustawieniami.
Wszystkie te elementy można skonfigurować w pliku manifest.json. W tym artykule nie będę jednak omawiał samej konfiguracji rozszerzenia, bo informacje na ten temat są łatwo dostępne w Internecie. Skupię się za to na różnicach w konfiguracji specyficznymi dla Angulara.
Praktyka
Co zrobić, żeby plik manifest.json pojawiał się w zbudowanej wersji aplikacji?
Najpierw plik manifest.json musi znaleźć się w projekcie. Najlepiej umieścić go w folderze /src
. Trzeba pamiętać o tym, że plik manifest.json zaraz po zbudowaniu naszej aplikacji powinien się znaleźć w głównym katalogu /dist
(bądź jego odpowiedniku).
Następnie musimy w pliku angular.json dodać nasz plik manifest.json do assetów. W moim przypadku wyglądało to tak:
"aot": true,
"assets": [
"src/assets",
"src/manifest.json"
],
"styles": [
"src/styles.scss"
],
Bloki assets (dwa na projekt) znajdują się w pliku angular.json w projects
-> extension
-> architect
-> build/test
-> options
. Prawdopodobnie u Ciebie extension jest zastąpione Twoją własną nazwą projektu.
Jak uruchomić rozszerzenie w przeglądarce?
Aby uruchomić rozszerzenie w przeglądarce musimy zacząć od przejścia pod adres chrome://extensions/
. Przeniesie nas on do ekranu głównego rozszerzeń.
Alternatywnie możemy dostać się do niego z okna ustawień przeglądarki.
Po wejściu na tę stronę w prawym górnym rogu ekranu będziemy mogli włączyć tryb deweloperski, który umożliwi używanie nieautoryzowanych przez Google rozszerzeń, w tym również testowych wersji tworzonej aplikacji.
Po uruchomieniu tego trybu uzyskamy dostęp do paska z trzema opcjami:
Interesuje nas pierwszy przycisk (Load unpacked). Po jego kliknięciu należy wybrać folder ze zbudowanym już rozszerzeniem.
Co zrobić, żeby z każdą zmianą nie budować aplikacji na nowo?
Niestety technicznie jest to niemożliwe. Nie pozwala na to sposób działania rozszerzenia.
Można jednak podczas budowania aplikacji użyć komendy ng build --watch
. Flaga --watch
będzie uruchamiać komendę ng build
za każdym razem, gdy pliki projektu zostaną zaktualizowane. Jeżeli zmiany będą dotyczyć jedynie plików popup lub options, to zostaną naniesione niemal natychmiast.
Ze względu na działanie content script i background, konieczne jest odpowiednie przeładowanie strony, na której chcemy przetestować zmiany, bądź odświeżenie całego rozszerzenia.
Aby odświeżyć cały plugin, wchodzimy na wcześniej opisaną stronę chrome://extensions/
, odnajdujemy tam rozszerzenie i klikamy w przycisk przeładowania.
Jak skonfigurować popup, options, background i content cript w pliku manifest.json?
To największy problem, na jaki natrafiłem podczas mojego researchu i domyślam się, że większość z Was weszła w ten artykuł, aby dowiedzieć się, jak go rozwiązać.
Bez problemu możemy w manifest.json wskazać ścieżkę do samego popupu, np. w ten sposób:
"browser_action": {
"default_title": "Trackfunnel",
"default_popup": "extension/index.html"
},
Gdy jednak będziemy chcieli w manifest.json wskazać ścieżki do wszystkich czterech elementów, szybko okaże się, że nie jest to takie proste.
Udało mi się jednak znaleźć trzy rozwiązania, a ich użyteczność może zależeć od specyfiki projektu, dlatego postaram się opisać wszystkie.
Należy jednak pamiętać, że załączenie content script jest możliwe tylko z wykorzystaniem pierwszego sposobu.
Sposób 1
Po pierwsze możemy stworzyć skrypty w plikach .js lub .ts, które podczas budowania naszej aplikacji zostaną skopiowane do folderu wynikowego. Wystarczy jedynie odpowiednie pliki umieścić w folderze Angulara (np. w folderze /src/scripts), a następnie w pliku angular.json należy poinformować kompilator, jak powinien je potraktować.
W moim przypadku chciałem jedynie po przebudowaniu aplikacji utworzyć plik contentscript.js
. Dodałem więc w pliku angular.json w sekcji project
-> extension
-> architect
-> build
lub test
-> scripts
linijkę:
{ "input": "src/app/scripts/content.script.ts", "bundleName": "contentscript" }
Dzięki tej informacji, po kompilacji, w folderze dist (bądź jego odpowiedniku) pojawi się plik contentscript.js
.
Musimy jeszcze pamiętać o zaktualizowaniu informacji o rozszerzeniu w manifest.json np. przez dodanie ścieżki do pliku contentscript.js:
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"js": [
"contentscript.js"
]
}
],
Wyżej opisane rozwiązanie jest bardzo proste, ale ma jednak dużą wadę. Przygotowane skrypty nie są częścią Angulara, przez co nie mamy do niego dostępu wewnątrz skryptów,, więc tracimy wszystkie korzyści płynące z używania tego frameworka. Ze względu na ograniczenia, rozwiązanie to sprawdzi się w projektach, które nie będą bardzo rozbudowane. W przeciwnym wypadku polecam rozważyć dwa inne rozwiązania
Sposób 2
Jednym z nich jest takie skonfigurowanie aplikacji, żeby po wejściu na odpowiedni route uruchamiał się odpowiedni element. Aby to zrobić, musimy do naszego głównego modułu w sekcji providers
dodać tę linijkę:
{ provide: LocationStrategy, useClass: HashLocationStrategy }
A następnie zaktualizować odpowiedni import w głównym module z routingiem o ustawienie useHash: true
. W moim przypadku wyglądało to tak:
imports: [RouterModule.forRoot(routes, { useHash: true })],
Na samym końcu musimy zaktualizować jeszcze plik index.html
, zmieniając fragment <base href="/">
na <base href="/index.html#/">
i od tej pory możemy już połączyć wszystkie elementy w jedno rozszerzenie w pliku manifest.json. Przykładowo, żeby skonfigurować poprawnie background
, dodaję taką sekcję:
"background": {
"page": "/index.html#/background",
"persistent": false
}
Sposób 3
Ostatnią opcją jest podzielenie jednego projektu Angulara na kilka mniejszych. Wystarczy, że użyjemy komendy ng generate application background
, która utworzy nam subprojekt o nazwie background
, który następnie musimy zbudować za pomocą ng serve --project background
. Wygenerowany kod konfigurujemy w pliku manifest.json analogicznie do tego, jak przedstawiłem to wyżej (w sposobie 1). Więcej na ten temat można przeczytać w dokumentacji.
Jak dodać komponent Angulara do strony internetowej?
Załączony content script, ze względu na sposób działania pluginów przeglądarkowych, uniemożliwia nam użycie w nim Angulara. Może to utrudnić tworzenie rozwiązań, które ingerują w działanie i wyświetlanie się stron internetowych. W takich sytuacjach z pomocą przychodzi nam jednak Angular Elements, który umożliwia nam tworzenie własnych Web Components. Jest to jednak bardzo rozbudowany temat, którego opisania nie podejmę się w tym artykule. Jego analizowanie polecam zacząć od dokumentacji.
Mam nadzieję, że moje rady choć trochę pomogą Wam w stworzeniu wymarzonych aplikacji!