mirror of
https://github.com/abhijithvijayan/web-extension-starter.git
synced 2026-01-30 09:48:12 +01:00
Setup basic trading enhancements
This commit is contained in:
parent
041527e7a4
commit
5f9f1faa93
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"tabWidth": 4,
|
||||||
|
"useTabs": false
|
||||||
|
}
|
||||||
27598
package-lock.json
generated
Normal file
27598
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
source/ContentScript/element-factories/owns-badge.ts
Normal file
18
source/ContentScript/element-factories/owns-badge.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import Trader from "../trader";
|
||||||
|
|
||||||
|
export default class OwnsBadge {
|
||||||
|
static create(trader: Trader): HTMLSpanElement {
|
||||||
|
let badge = document.createElement("a");
|
||||||
|
badge.classList.add("et-badge");
|
||||||
|
|
||||||
|
if (trader.ownsList !== null) {
|
||||||
|
badge.href = trader.ownsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
let recordings = trader.wantsCount === 1 ? "recording" : "recordings";
|
||||||
|
|
||||||
|
badge.innerHTML = `Owns <strong style="font-weight: semibold; color: #0f172a;">${trader.ownsCount} ${recordings}</strong> that I want`;
|
||||||
|
|
||||||
|
return badge;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
source/ContentScript/element-factories/star.ts
Normal file
26
source/ContentScript/element-factories/star.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
export default class Star {
|
||||||
|
static create(): SVGElement {
|
||||||
|
let svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||||
|
svg.setAttribute("height", "1em");
|
||||||
|
svg.setAttribute("viewBox", "0 0 576 512");
|
||||||
|
svg.style.position = "absolute";
|
||||||
|
svg.style.top = "0";
|
||||||
|
svg.style.left = "-28px";
|
||||||
|
svg.style.width = "20px";
|
||||||
|
svg.style.height = "20px";
|
||||||
|
|
||||||
|
let path = document.createElementNS(
|
||||||
|
"http://www.w3.org/2000/svg",
|
||||||
|
"path"
|
||||||
|
);
|
||||||
|
path.setAttribute(
|
||||||
|
"d",
|
||||||
|
"M316.9 18C311.6 7 300.4 0 288.1 0s-23.4 7-28.8 18L195 150.3 51.4 171.5c-12 1.8-22 10.2-25.7 21.7s-.7 24.2 7.9 32.7L137.8 329 113.2 474.7c-2 12 3 24.2 12.9 31.3s23 8 33.8 2.3l128.3-68.5 128.3 68.5c10.8 5.7 23.9 4.9 33.8-2.3s14.9-19.3 12.9-31.3L438.5 329 542.7 225.9c8.6-8.5 11.7-21.2 7.9-32.7s-13.7-19.9-25.7-21.7L381.2 150.3 316.9 18z"
|
||||||
|
);
|
||||||
|
path.setAttribute("fill", "#f59e0b");
|
||||||
|
|
||||||
|
svg.appendChild(path);
|
||||||
|
|
||||||
|
return svg;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
source/ContentScript/element-factories/wants-badge.ts
Normal file
18
source/ContentScript/element-factories/wants-badge.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import Trader from "../trader";
|
||||||
|
|
||||||
|
export default class WantsBadge {
|
||||||
|
static create(trader: Trader): HTMLSpanElement {
|
||||||
|
let badge = document.createElement("a");
|
||||||
|
badge.classList.add("et-badge");
|
||||||
|
|
||||||
|
if (trader.wantsList !== null) {
|
||||||
|
badge.href = trader.wantsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
let recordings = trader.wantsCount === 1 ? "recording" : "recordings";
|
||||||
|
|
||||||
|
badge.innerHTML = `Wants <strong style="font-weight: semibold; color: #0f172a;">${trader.wantsCount} ${recordings}</strong> that I own`;
|
||||||
|
|
||||||
|
return badge;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,3 +1,10 @@
|
|||||||
console.log('helloworld from content script');
|
import WhoOwnsEnhancer from "./page-enhancers/who-owns-enhancer";
|
||||||
|
import WhoWantsEnhancer from "./page-enhancers/who-wants-enhancer";
|
||||||
|
|
||||||
export {};
|
if (window.location.href.includes("who-owns.php")) {
|
||||||
|
WhoOwnsEnhancer.enhance(document);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.location.href.includes("who-wants.php")) {
|
||||||
|
WhoWantsEnhancer.enhance(document);
|
||||||
|
}
|
||||||
|
|||||||
79
source/ContentScript/page-elements/profile-link.ts
Normal file
79
source/ContentScript/page-elements/profile-link.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import OwnsBadge from "../element-factories/owns-badge";
|
||||||
|
import Star from "../element-factories/star";
|
||||||
|
import WantsBadge from "../element-factories/wants-badge";
|
||||||
|
import Trader from "../trader";
|
||||||
|
import TraderRepository from "../trader-repository";
|
||||||
|
|
||||||
|
export default class ProfileLink {
|
||||||
|
constructor(
|
||||||
|
public element: HTMLAnchorElement,
|
||||||
|
public traderRepository: TraderRepository
|
||||||
|
) {}
|
||||||
|
|
||||||
|
get username(): string {
|
||||||
|
return this.element.innerText.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
get profile(): string {
|
||||||
|
return this.element.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
get trader(): Trader | null {
|
||||||
|
return this.traderRepository.find(this.username);
|
||||||
|
}
|
||||||
|
|
||||||
|
get lastElement(): Element {
|
||||||
|
return this.element.nextElementSibling?.tagName === "SPAN"
|
||||||
|
? this.element.nextElementSibling!
|
||||||
|
: this.element;
|
||||||
|
}
|
||||||
|
|
||||||
|
addOwnsBadge() {
|
||||||
|
let trader = this.trader;
|
||||||
|
|
||||||
|
if (trader === null) {
|
||||||
|
throw new Error(
|
||||||
|
"Cannot add owns badge to a profile link that has no trader data"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let badge = OwnsBadge.create(this.trader!);
|
||||||
|
|
||||||
|
this.lastElement.insertAdjacentElement("afterend", badge);
|
||||||
|
}
|
||||||
|
|
||||||
|
addWantsBadge() {
|
||||||
|
let trader = this.trader;
|
||||||
|
|
||||||
|
if (trader === null) {
|
||||||
|
throw new Error(
|
||||||
|
"Cannot add wants badge to a profile link that has no trader data"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let badge = WantsBadge.create(this.trader!);
|
||||||
|
|
||||||
|
this.lastElement.insertAdjacentElement("afterend", badge);
|
||||||
|
}
|
||||||
|
|
||||||
|
addStar() {
|
||||||
|
let star = Star.create();
|
||||||
|
|
||||||
|
this.element.style.position = "relative";
|
||||||
|
this.element.style.fontWeight = "bold";
|
||||||
|
|
||||||
|
this.element.appendChild(star);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getAll(page: Document, traderRepository: TraderRepository) {
|
||||||
|
return Array.from(
|
||||||
|
page.querySelectorAll('a[href*="/profile/view-profile.php?id="]')
|
||||||
|
).map(
|
||||||
|
(profileLink) =>
|
||||||
|
new ProfileLink(
|
||||||
|
profileLink as HTMLAnchorElement,
|
||||||
|
traderRepository
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
source/ContentScript/page-enhancers/who-owns-enhancer.ts
Normal file
22
source/ContentScript/page-enhancers/who-owns-enhancer.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import ProfileLink from "../page-elements/profile-link";
|
||||||
|
import TraderRepository from "../trader-repository";
|
||||||
|
|
||||||
|
export default class WhoOwnsEnhancer {
|
||||||
|
static async enhance(page: Document) {
|
||||||
|
let repository = await TraderRepository.load();
|
||||||
|
|
||||||
|
ProfileLink.getAll(page, repository)
|
||||||
|
.filter((profileLink) => profileLink.trader !== null)
|
||||||
|
.filter((profileLink) => profileLink.trader!.wantsCount !== null)
|
||||||
|
.filter((profileLink) => profileLink.trader!.wantsCount! > 0)
|
||||||
|
.map((profileLink) => {
|
||||||
|
profileLink.addWantsBadge();
|
||||||
|
|
||||||
|
return profileLink;
|
||||||
|
})
|
||||||
|
.filter((profileLink) => profileLink.trader!.open)
|
||||||
|
.forEach((profileLink) => {
|
||||||
|
profileLink.addStar();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
22
source/ContentScript/page-enhancers/who-wants-enhancer.ts
Normal file
22
source/ContentScript/page-enhancers/who-wants-enhancer.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import ProfileLink from "../page-elements/profile-link";
|
||||||
|
import TraderRepository from "../trader-repository";
|
||||||
|
|
||||||
|
export default class WhoWantsEnhancer {
|
||||||
|
static async enhance(page: Document) {
|
||||||
|
let repository = await TraderRepository.load();
|
||||||
|
|
||||||
|
ProfileLink.getAll(page, repository)
|
||||||
|
.filter((profileLink) => profileLink.trader !== null)
|
||||||
|
.filter((profileLink) => profileLink.trader!.ownsCount !== null)
|
||||||
|
.filter((profileLink) => profileLink.trader!.ownsCount! > 0)
|
||||||
|
.map((profileLink) => {
|
||||||
|
profileLink.addOwnsBadge();
|
||||||
|
|
||||||
|
return profileLink;
|
||||||
|
})
|
||||||
|
.filter((profileLink) => profileLink.trader!.open)
|
||||||
|
.forEach((profileLink) => {
|
||||||
|
profileLink.addStar();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
127
source/ContentScript/trader-repository.ts
Normal file
127
source/ContentScript/trader-repository.ts
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import { browser } from "webextension-polyfill-ts";
|
||||||
|
import Trader from "./trader";
|
||||||
|
|
||||||
|
export default class TraderRepository {
|
||||||
|
page: Document;
|
||||||
|
traders: Trader[];
|
||||||
|
|
||||||
|
constructor(traders: Trader[] = []) {
|
||||||
|
this.traders = traders;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async load(): Promise<TraderRepository> {
|
||||||
|
if (!(await this.hasTradersInStorage())) {
|
||||||
|
await this.refreshGlobalTradersStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
let traders = await this.loadTradersFromStorage();
|
||||||
|
|
||||||
|
return new TraderRepository(traders!);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the traders who want my items from the Encora website.
|
||||||
|
*/
|
||||||
|
static async fetchTradersWhoWantMyItems(): Promise<Trader[]> {
|
||||||
|
const response = await fetch(
|
||||||
|
"https://encora.it/profile/trade_finder_theirs.php"
|
||||||
|
);
|
||||||
|
let text = await response.text();
|
||||||
|
let page = new DOMParser().parseFromString(text, "text/html");
|
||||||
|
|
||||||
|
let table = page.querySelector("table")!;
|
||||||
|
let rows = table.querySelectorAll("tr");
|
||||||
|
|
||||||
|
return Array.from(rows)
|
||||||
|
.map((row) => Trader.fromWantsRow(row as HTMLTableRowElement))
|
||||||
|
.filter((trader) => trader !== null) as Trader[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the traders who own my wants from the Encora website.
|
||||||
|
*/
|
||||||
|
static async fetchTradersWhoOwnMyWants(): Promise<Trader[]> {
|
||||||
|
const response = await fetch(
|
||||||
|
"https://encora.it/profile/trade_finder.php"
|
||||||
|
);
|
||||||
|
let text = await response.text();
|
||||||
|
let page = new DOMParser().parseFromString(text, "text/html");
|
||||||
|
|
||||||
|
let table = page.querySelector("table")!;
|
||||||
|
let rows = table.querySelectorAll("tr");
|
||||||
|
|
||||||
|
return Array.from(rows)
|
||||||
|
.map((row) => Trader.fromOwnsRow(row as HTMLTableRowElement))
|
||||||
|
.filter((trader) => trader !== null) as Trader[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches the traders who want my items and the traders who own my wants
|
||||||
|
* from the Encora website and stores them in the global storage.
|
||||||
|
*/
|
||||||
|
static async refreshGlobalTradersStorage() {
|
||||||
|
let [wantsTraders, ownsTraders] = await Promise.all([
|
||||||
|
this.fetchTradersWhoWantMyItems(),
|
||||||
|
this.fetchTradersWhoOwnMyWants(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let traders = Trader.mergeLists(wantsTraders, ownsTraders).map(
|
||||||
|
(trader) => trader.toJSON()
|
||||||
|
);
|
||||||
|
|
||||||
|
browser.storage.local.set({ traders: traders });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the global storage has traders.
|
||||||
|
*/
|
||||||
|
static async hasTradersInStorage(): Promise<boolean> {
|
||||||
|
let storage = await browser.storage.local.get("traders");
|
||||||
|
|
||||||
|
return storage.traders != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the traders from the global storage.
|
||||||
|
*/
|
||||||
|
static async loadTradersFromStorage(): Promise<Trader[]> {
|
||||||
|
let storage = await browser.storage.local.get("traders");
|
||||||
|
let traders = storage.traders;
|
||||||
|
|
||||||
|
if (traders == null) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return traders.map((trader: any) => Trader.fromJSON(trader));
|
||||||
|
}
|
||||||
|
|
||||||
|
find(username: string): Trader | null {
|
||||||
|
return (
|
||||||
|
this.traders.find((trader) => trader.username === username) ?? null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static loadFromWhoOwnsPage(page: Document): TraderRepository {
|
||||||
|
let traders = Array.from(
|
||||||
|
page.querySelectorAll('a[href*="/profile/view-profile.php?id="]')
|
||||||
|
)
|
||||||
|
.map((profileLink) =>
|
||||||
|
Trader.fromProfileLink(profileLink as HTMLAnchorElement)
|
||||||
|
)
|
||||||
|
.filter((trader) => trader !== null);
|
||||||
|
|
||||||
|
return new TraderRepository(traders);
|
||||||
|
}
|
||||||
|
|
||||||
|
add(trader: Trader) {
|
||||||
|
this.traders.push(trader);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAll(): Trader[] {
|
||||||
|
return this.traders;
|
||||||
|
}
|
||||||
|
|
||||||
|
getOpen(): Trader[] {
|
||||||
|
return this.traders.filter((trader) => trader.open);
|
||||||
|
}
|
||||||
|
}
|
||||||
189
source/ContentScript/trader.ts
Normal file
189
source/ContentScript/trader.ts
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
interface RowData {
|
||||||
|
username: string;
|
||||||
|
profile: string;
|
||||||
|
open: boolean;
|
||||||
|
count: number;
|
||||||
|
list: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Trader {
|
||||||
|
constructor(
|
||||||
|
public username: string,
|
||||||
|
public profile: string,
|
||||||
|
public open: boolean | null,
|
||||||
|
public ownsCount: number | null = null,
|
||||||
|
public ownsList: string | null = null,
|
||||||
|
public wantsCount: number | null = null,
|
||||||
|
public wantsList: string | null = null
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the underlying trader data from a row in a "Trade finder" table.
|
||||||
|
*/
|
||||||
|
static parseRow(row: HTMLTableRowElement): RowData | null {
|
||||||
|
let cells = row.querySelectorAll("td");
|
||||||
|
|
||||||
|
if (cells.length < 2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let profileLink = cells[0].querySelector("a");
|
||||||
|
|
||||||
|
if (!profileLink) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let username =
|
||||||
|
profileLink.querySelector("strong")?.innerText ??
|
||||||
|
profileLink.innerText;
|
||||||
|
let profile = profileLink.href;
|
||||||
|
|
||||||
|
let open =
|
||||||
|
cells[0]
|
||||||
|
.querySelector("span")
|
||||||
|
?.innerText.includes("Open to trades") ?? false;
|
||||||
|
|
||||||
|
let wantsLink = cells[1].querySelector("a");
|
||||||
|
|
||||||
|
let count = wantsLink
|
||||||
|
? parseInt(wantsLink.innerText.match(/\d+/)![0])
|
||||||
|
: 0;
|
||||||
|
let list = wantsLink ? wantsLink.href : null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
username,
|
||||||
|
profile,
|
||||||
|
open,
|
||||||
|
count,
|
||||||
|
list,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Trader from a row in a "Trade finder wants" table.
|
||||||
|
*/
|
||||||
|
static fromWantsRow(row: HTMLTableRowElement): Trader | null {
|
||||||
|
let data = Trader.parseRow(row);
|
||||||
|
|
||||||
|
if (data === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Trader(
|
||||||
|
data.username,
|
||||||
|
data.profile,
|
||||||
|
data.open,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
data.count,
|
||||||
|
data.list
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Trader from a row in a "Trade finder owns" table.
|
||||||
|
*/
|
||||||
|
static fromOwnsRow(row: HTMLTableRowElement): Trader | null {
|
||||||
|
let data = Trader.parseRow(row);
|
||||||
|
|
||||||
|
if (data === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Trader(
|
||||||
|
data.username,
|
||||||
|
data.profile,
|
||||||
|
data.open,
|
||||||
|
data.count,
|
||||||
|
data.list,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Trader from a profile link.
|
||||||
|
*/
|
||||||
|
static fromProfileLink(profileLink: HTMLAnchorElement) {
|
||||||
|
let username = profileLink.innerText.trim();
|
||||||
|
let profile = profileLink.href;
|
||||||
|
|
||||||
|
let open = null;
|
||||||
|
|
||||||
|
if (profileLink.nextElementSibling?.nodeName === "SPAN") {
|
||||||
|
open = (<HTMLSpanElement>(
|
||||||
|
profileLink.nextElementSibling
|
||||||
|
)).innerText.includes("Open to trades");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Trader(username, profile, open, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge two traders together.
|
||||||
|
*/
|
||||||
|
merge(trader: Trader): Trader {
|
||||||
|
return new Trader(
|
||||||
|
this.username,
|
||||||
|
this.profile,
|
||||||
|
this.open ?? trader.open,
|
||||||
|
this.ownsCount ?? trader.ownsCount,
|
||||||
|
this.ownsList ?? trader.ownsList,
|
||||||
|
this.wantsCount ?? trader.wantsCount,
|
||||||
|
this.wantsList ?? trader.wantsList
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge two lists of traders together.
|
||||||
|
*/
|
||||||
|
static mergeLists(list1: Trader[], list2: Trader[]): Trader[] {
|
||||||
|
let merged = list1.map((trader) => {
|
||||||
|
let trader2 = list2.find((t) => t.username === trader.username);
|
||||||
|
|
||||||
|
if (trader2 === undefined) {
|
||||||
|
return trader;
|
||||||
|
}
|
||||||
|
|
||||||
|
return trader.merge(trader2);
|
||||||
|
});
|
||||||
|
|
||||||
|
merged.push(
|
||||||
|
...list2.filter(
|
||||||
|
(trader) => !merged.some((t) => t.username === trader.username)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Trader to a JSON object.
|
||||||
|
*/
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
username: this.username,
|
||||||
|
profile: this.profile,
|
||||||
|
open: this.open,
|
||||||
|
ownsCount: this.ownsCount,
|
||||||
|
ownsList: this.ownsList,
|
||||||
|
wantsCount: this.wantsCount,
|
||||||
|
wantsList: this.wantsList,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a JSON object to a Trader.
|
||||||
|
*/
|
||||||
|
static fromJSON(json: any) {
|
||||||
|
return new Trader(
|
||||||
|
json.username,
|
||||||
|
json.profile,
|
||||||
|
json.open,
|
||||||
|
json.ownsCount,
|
||||||
|
json.ownsList,
|
||||||
|
json.wantsCount,
|
||||||
|
json.wantsList
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,34 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import './styles.scss';
|
|
||||||
|
|
||||||
const Options: React.FC = () => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<form>
|
|
||||||
<p>
|
|
||||||
<label htmlFor="username">Your Name</label>
|
|
||||||
<br />
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="username"
|
|
||||||
name="username"
|
|
||||||
spellCheck="false"
|
|
||||||
autoComplete="off"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<label htmlFor="logging">
|
|
||||||
<input type="checkbox" name="logging" /> Show the features enabled
|
|
||||||
on each page in the console
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<p>cool cool cool</p>
|
|
||||||
</p>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Options;
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
|
|
||||||
import Options from './Options';
|
|
||||||
|
|
||||||
ReactDOM.render(<Options />, document.getElementById('options-root'));
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
@import "../styles/fonts";
|
|
||||||
@import "../styles/reset";
|
|
||||||
@import "../styles/variables";
|
|
||||||
|
|
||||||
@import "~webext-base-css/webext-base.css";
|
|
||||||
|
|
||||||
body {
|
|
||||||
color: $black;
|
|
||||||
background-color: $greyWhite;
|
|
||||||
}
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import {browser, Tabs} from 'webextension-polyfill-ts';
|
|
||||||
|
|
||||||
import './styles.scss';
|
|
||||||
|
|
||||||
function openWebPage(url: string): Promise<Tabs.Tab> {
|
|
||||||
return browser.tabs.create({url});
|
|
||||||
}
|
|
||||||
|
|
||||||
const Popup: React.FC = () => {
|
|
||||||
return (
|
|
||||||
<section id="popup">
|
|
||||||
<h2>WEB-EXTENSION-STARTER</h2>
|
|
||||||
<button
|
|
||||||
id="options__button"
|
|
||||||
type="button"
|
|
||||||
onClick={(): Promise<Tabs.Tab> => {
|
|
||||||
return openWebPage('options.html');
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Options Page
|
|
||||||
</button>
|
|
||||||
<div className="links__holder">
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={(): Promise<Tabs.Tab> => {
|
|
||||||
return openWebPage(
|
|
||||||
'https://github.com/abhijithvijayan/web-extension-starter'
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
GitHub
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={(): Promise<Tabs.Tab> => {
|
|
||||||
return openWebPage(
|
|
||||||
'https://www.buymeacoffee.com/abhijithvijayan'
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Buy Me A Coffee
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Popup;
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
|
|
||||||
import Popup from './Popup';
|
|
||||||
|
|
||||||
ReactDOM.render(<Popup />, document.getElementById('popup-root'));
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
@import "../styles/fonts";
|
|
||||||
@import "../styles/reset";
|
|
||||||
@import "../styles/variables";
|
|
||||||
|
|
||||||
body {
|
|
||||||
color: $black;
|
|
||||||
background-color: $greyWhite;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#popup {
|
|
||||||
min-width: 350px;
|
|
||||||
padding: 30px 20px;
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 25px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#options__button {
|
|
||||||
width: 50%;
|
|
||||||
background: green;
|
|
||||||
color: white;
|
|
||||||
font-weight: 500;
|
|
||||||
border-radius: 15px;
|
|
||||||
padding: 5px 10px;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 20px auto;
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: 0.8;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.links__holder {
|
|
||||||
ul {
|
|
||||||
display: flex;
|
|
||||||
margin-top: 1em;
|
|
||||||
justify-content: space-around;
|
|
||||||
|
|
||||||
li {
|
|
||||||
button {
|
|
||||||
border-radius: 25px;
|
|
||||||
font-size: 20px;
|
|
||||||
font-weight: 600;
|
|
||||||
padding: 10px 17px;
|
|
||||||
background-color: rgba(0, 0, 255, 0.7);
|
|
||||||
color: white;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
14
source/assets/css/extension.css
Normal file
14
source/assets/css/extension.css
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
.et-badge {
|
||||||
|
background-color: #e2e8f0;
|
||||||
|
color: #334155;
|
||||||
|
font-size: 0.6em;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 2px 6px;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.et-badge:hover {
|
||||||
|
background-color: #cbd5e1;
|
||||||
|
color: #020617;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.9 KiB |
BIN
source/assets/icons/tools-48.png
Normal file
BIN
source/assets/icons/tools-48.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 916 B |
BIN
source/assets/icons/tools-96.png
Normal file
BIN
source/assets/icons/tools-96.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@ -1,30 +1,27 @@
|
|||||||
{
|
{
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "Sample WebExtension",
|
"name": "Encora Tools",
|
||||||
"version": "0.0.0",
|
"version": "0.0.1",
|
||||||
|
|
||||||
"icons": {
|
"icons": {
|
||||||
"16": "assets/icons/favicon-16.png",
|
"48": "assets/icons/tools-48.png",
|
||||||
"32": "assets/icons/favicon-32.png",
|
"96": "assets/icons/tools-96.png"
|
||||||
"48": "assets/icons/favicon-48.png",
|
|
||||||
"128": "assets/icons/favicon-128.png"
|
|
||||||
},
|
},
|
||||||
"description": "Sample description",
|
"description": "Adds extra features to the Encora trading site.",
|
||||||
"homepage_url": "https://github.com/abhijithvijayan/web-extension-starter",
|
"homepage_url": "https://musicalbean.carrd.co",
|
||||||
"short_name": "Sample Name",
|
"short_name": "Encora Tools",
|
||||||
|
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"activeTab",
|
"activeTab",
|
||||||
"storage",
|
"storage",
|
||||||
"http://*/*",
|
"webRequest"
|
||||||
"https://*/*"
|
|
||||||
],
|
],
|
||||||
|
|
||||||
"content_security_policy": "script-src 'self'; object-src 'self'",
|
"content_security_policy": "script-src 'self'; object-src 'self'",
|
||||||
|
|
||||||
"__chrome|firefox__author": "abhijithvijayan",
|
"__chrome|firefox__author": "musicalbean",
|
||||||
"__opera__developer": {
|
"__opera__developer": {
|
||||||
"name": "abhijithvijayan"
|
"name": "musicalbean"
|
||||||
},
|
},
|
||||||
|
|
||||||
"__firefox__applications": {
|
"__firefox__applications": {
|
||||||
@ -36,26 +33,6 @@
|
|||||||
"__chrome__minimum_chrome_version": "49",
|
"__chrome__minimum_chrome_version": "49",
|
||||||
"__opera__minimum_opera_version": "36",
|
"__opera__minimum_opera_version": "36",
|
||||||
|
|
||||||
"browser_action": {
|
|
||||||
"default_popup": "popup.html",
|
|
||||||
"default_icon": {
|
|
||||||
"16": "assets/icons/favicon-16.png",
|
|
||||||
"32": "assets/icons/favicon-32.png",
|
|
||||||
"48": "assets/icons/favicon-48.png",
|
|
||||||
"128": "assets/icons/favicon-128.png"
|
|
||||||
},
|
|
||||||
"default_title": "tiny title",
|
|
||||||
"__chrome|opera__chrome_style": false,
|
|
||||||
"__firefox__browser_style": false
|
|
||||||
},
|
|
||||||
|
|
||||||
"__chrome|opera__options_page": "options.html",
|
|
||||||
"options_ui": {
|
|
||||||
"page": "options.html",
|
|
||||||
"open_in_tab": true,
|
|
||||||
"__chrome__chrome_style": false
|
|
||||||
},
|
|
||||||
|
|
||||||
"background": {
|
"background": {
|
||||||
"scripts": [
|
"scripts": [
|
||||||
"js/background.bundle.js"
|
"js/background.bundle.js"
|
||||||
@ -65,11 +42,13 @@
|
|||||||
|
|
||||||
"content_scripts": [{
|
"content_scripts": [{
|
||||||
"matches": [
|
"matches": [
|
||||||
"http://*/*",
|
"*://*.encora.it/*"
|
||||||
"https://*/*"
|
|
||||||
],
|
],
|
||||||
"js": [
|
"js": [
|
||||||
"js/contentScript.bundle.js"
|
"js/contentScript.bundle.js"
|
||||||
|
],
|
||||||
|
"css": [
|
||||||
|
"assets/css/extension.css"
|
||||||
]
|
]
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
@ -1 +0,0 @@
|
|||||||
@import url("https://fonts.googleapis.com/css?family=Nunito:400,600");
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
@import '~advanced-css-reset/dist/reset.css';
|
|
||||||
|
|
||||||
// Add your custom reset rules here
|
|
||||||
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 0;
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
// colors
|
|
||||||
$black: #0d0d0d;
|
|
||||||
$greyWhite: #f3f3f3;
|
|
||||||
$skyBlue: #8892b0;
|
|
||||||
|
|
||||||
// fonts
|
|
||||||
$nunito: "Nunito", sans-serif;
|
|
||||||
|
|
||||||
// font weights
|
|
||||||
$thin: 100;
|
|
||||||
$exlight: 200;
|
|
||||||
$light: 300;
|
|
||||||
$regular: 400;
|
|
||||||
$medium: 500;
|
|
||||||
$semibold: 600;
|
|
||||||
$bold: 700;
|
|
||||||
$exbold: 800;
|
|
||||||
$exblack: 900;
|
|
||||||
|
|
||||||
// other variables
|
|
||||||
.d-none {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Options</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="options-root"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=500" />
|
|
||||||
<title>Popup</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="popup-root"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@ -1,32 +1,32 @@
|
|||||||
const path = require('path');
|
const path = require("path");
|
||||||
const webpack = require('webpack');
|
const webpack = require("webpack");
|
||||||
const FilemanagerPlugin = require('filemanager-webpack-plugin');
|
const FilemanagerPlugin = require("filemanager-webpack-plugin");
|
||||||
const TerserPlugin = require('terser-webpack-plugin');
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||||
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
|
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||||
const ExtensionReloader = require('webpack-extension-reloader');
|
const ExtensionReloader = require("webpack-extension-reloader");
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
const WextManifestWebpackPlugin = require('wext-manifest-webpack-plugin');
|
const WextManifestWebpackPlugin = require("wext-manifest-webpack-plugin");
|
||||||
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
|
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
|
||||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
|
||||||
|
|
||||||
const viewsPath = path.join(__dirname, 'views');
|
const viewsPath = path.join(__dirname, "views");
|
||||||
const sourcePath = path.join(__dirname, 'source');
|
const sourcePath = path.join(__dirname, "source");
|
||||||
const destPath = path.join(__dirname, 'extension');
|
const destPath = path.join(__dirname, "extension");
|
||||||
const nodeEnv = process.env.NODE_ENV || 'development';
|
const nodeEnv = process.env.NODE_ENV || "development";
|
||||||
const targetBrowser = process.env.TARGET_BROWSER;
|
const targetBrowser = process.env.TARGET_BROWSER;
|
||||||
|
|
||||||
const extensionReloaderPlugin =
|
const extensionReloaderPlugin =
|
||||||
nodeEnv === 'development'
|
nodeEnv === "development"
|
||||||
? new ExtensionReloader({
|
? new ExtensionReloader({
|
||||||
port: 9090,
|
port: 9090,
|
||||||
reloadPage: true,
|
reloadPage: true,
|
||||||
entries: {
|
entries: {
|
||||||
// TODO: reload manifest on update
|
// TODO: reload manifest on update
|
||||||
contentScript: 'contentScript',
|
contentScript: "contentScript",
|
||||||
background: 'background',
|
background: "background",
|
||||||
extensionPage: ['popup', 'options'],
|
extensionPage: ["popup", "options"],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
: () => {
|
: () => {
|
||||||
@ -34,15 +34,15 @@ const extensionReloaderPlugin =
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getExtensionFileType = (browser) => {
|
const getExtensionFileType = (browser) => {
|
||||||
if (browser === 'opera') {
|
if (browser === "opera") {
|
||||||
return 'crx';
|
return "crx";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (browser === 'firefox') {
|
if (browser === "firefox") {
|
||||||
return 'xpi';
|
return "xpi";
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'zip';
|
return "zip";
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@ -58,23 +58,21 @@ module.exports = {
|
|||||||
mode: nodeEnv,
|
mode: nodeEnv,
|
||||||
|
|
||||||
entry: {
|
entry: {
|
||||||
manifest: path.join(sourcePath, 'manifest.json'),
|
manifest: path.join(sourcePath, "manifest.json"),
|
||||||
background: path.join(sourcePath, 'Background', 'index.ts'),
|
background: path.join(sourcePath, "Background", "index.ts"),
|
||||||
contentScript: path.join(sourcePath, 'ContentScript', 'index.ts'),
|
contentScript: path.join(sourcePath, "ContentScript", "index.ts"),
|
||||||
popup: path.join(sourcePath, 'Popup', 'index.tsx'),
|
|
||||||
options: path.join(sourcePath, 'Options', 'index.tsx'),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
output: {
|
output: {
|
||||||
path: path.join(destPath, targetBrowser),
|
path: path.join(destPath, targetBrowser),
|
||||||
filename: 'js/[name].bundle.js',
|
filename: "js/[name].bundle.js",
|
||||||
},
|
},
|
||||||
|
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.ts', '.tsx', '.js', '.json'],
|
extensions: [".ts", ".tsx", ".js", ".json"],
|
||||||
alias: {
|
alias: {
|
||||||
'webextension-polyfill-ts': path.resolve(
|
"webextension-polyfill-ts": path.resolve(
|
||||||
path.join(__dirname, 'node_modules', 'webextension-polyfill-ts')
|
path.join(__dirname, "node_modules", "webextension-polyfill-ts")
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -82,10 +80,10 @@ module.exports = {
|
|||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
type: 'javascript/auto', // prevent webpack handling json with its own loaders,
|
type: "javascript/auto", // prevent webpack handling json with its own loaders,
|
||||||
test: /manifest\.json$/,
|
test: /manifest\.json$/,
|
||||||
use: {
|
use: {
|
||||||
loader: 'wext-manifest-loader',
|
loader: "wext-manifest-loader",
|
||||||
options: {
|
options: {
|
||||||
usePackageJSONVersion: true, // set to false to not use package.json version for manifest
|
usePackageJSONVersion: true, // set to false to not use package.json version for manifest
|
||||||
},
|
},
|
||||||
@ -94,7 +92,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(js|ts)x?$/,
|
test: /\.(js|ts)x?$/,
|
||||||
loader: 'babel-loader',
|
loader: "babel-loader",
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -104,18 +102,18 @@ module.exports = {
|
|||||||
loader: MiniCssExtractPlugin.loader, // It creates a CSS file per JS file which contains CSS
|
loader: MiniCssExtractPlugin.loader, // It creates a CSS file per JS file which contains CSS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loader: 'css-loader', // Takes the CSS files and returns the CSS with imports and url(...) for Webpack
|
loader: "css-loader", // Takes the CSS files and returns the CSS with imports and url(...) for Webpack
|
||||||
options: {
|
options: {
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loader: 'postcss-loader',
|
loader: "postcss-loader",
|
||||||
options: {
|
options: {
|
||||||
postcssOptions: {
|
postcssOptions: {
|
||||||
plugins: [
|
plugins: [
|
||||||
[
|
[
|
||||||
'autoprefixer',
|
"autoprefixer",
|
||||||
{
|
{
|
||||||
// Options
|
// Options
|
||||||
},
|
},
|
||||||
@ -124,8 +122,8 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'resolve-url-loader', // Rewrites relative paths in url() statements
|
"resolve-url-loader", // Rewrites relative paths in url() statements
|
||||||
'sass-loader', // Takes the Sass/SCSS file and compiles to the CSS
|
"sass-loader", // Takes the Sass/SCSS file and compiles to the CSS
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -138,38 +136,26 @@ module.exports = {
|
|||||||
new webpack.SourceMapDevToolPlugin({ filename: false }),
|
new webpack.SourceMapDevToolPlugin({ filename: false }),
|
||||||
new ForkTsCheckerWebpackPlugin(),
|
new ForkTsCheckerWebpackPlugin(),
|
||||||
// environmental variables
|
// environmental variables
|
||||||
new webpack.EnvironmentPlugin(['NODE_ENV', 'TARGET_BROWSER']),
|
new webpack.EnvironmentPlugin(["NODE_ENV", "TARGET_BROWSER"]),
|
||||||
// delete previous build files
|
// delete previous build files
|
||||||
new CleanWebpackPlugin({
|
new CleanWebpackPlugin({
|
||||||
cleanOnceBeforeBuildPatterns: [
|
cleanOnceBeforeBuildPatterns: [
|
||||||
path.join(process.cwd(), `extension/${targetBrowser}`),
|
path.join(process.cwd(), `extension/${targetBrowser}`),
|
||||||
path.join(
|
path.join(
|
||||||
process.cwd(),
|
process.cwd(),
|
||||||
`extension/${targetBrowser}.${getExtensionFileType(targetBrowser)}`
|
`extension/${targetBrowser}.${getExtensionFileType(
|
||||||
|
targetBrowser
|
||||||
|
)}`
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
cleanStaleWebpackAssets: false,
|
cleanStaleWebpackAssets: false,
|
||||||
verbose: true,
|
verbose: true,
|
||||||
}),
|
}),
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: path.join(viewsPath, 'popup.html'),
|
|
||||||
inject: 'body',
|
|
||||||
chunks: ['popup'],
|
|
||||||
hash: true,
|
|
||||||
filename: 'popup.html',
|
|
||||||
}),
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: path.join(viewsPath, 'options.html'),
|
|
||||||
inject: 'body',
|
|
||||||
chunks: ['options'],
|
|
||||||
hash: true,
|
|
||||||
filename: 'options.html',
|
|
||||||
}),
|
|
||||||
// write css file(s) to build folder
|
// write css file(s) to build folder
|
||||||
new MiniCssExtractPlugin({filename: 'css/[name].css'}),
|
new MiniCssExtractPlugin({ filename: "css/[name].css" }),
|
||||||
// copy static assets
|
// copy static assets
|
||||||
new CopyWebpackPlugin({
|
new CopyWebpackPlugin({
|
||||||
patterns: [{from: 'source/assets', to: 'assets'}],
|
patterns: [{ from: "source/assets", to: "assets" }],
|
||||||
}),
|
}),
|
||||||
// plugin to enable browser reloading in development mode
|
// plugin to enable browser reloading in development mode
|
||||||
extensionReloaderPlugin,
|
extensionReloaderPlugin,
|
||||||
@ -189,7 +175,10 @@ module.exports = {
|
|||||||
}),
|
}),
|
||||||
new OptimizeCSSAssetsPlugin({
|
new OptimizeCSSAssetsPlugin({
|
||||||
cssProcessorPluginOptions: {
|
cssProcessorPluginOptions: {
|
||||||
preset: ['default', {discardComments: {removeAll: true}}],
|
preset: [
|
||||||
|
"default",
|
||||||
|
{ discardComments: { removeAll: true } },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
new FilemanagerPlugin({
|
new FilemanagerPlugin({
|
||||||
@ -197,9 +186,12 @@ module.exports = {
|
|||||||
onEnd: {
|
onEnd: {
|
||||||
archive: [
|
archive: [
|
||||||
{
|
{
|
||||||
format: 'zip',
|
format: "zip",
|
||||||
source: path.join(destPath, targetBrowser),
|
source: path.join(destPath, targetBrowser),
|
||||||
destination: `${path.join(destPath, targetBrowser)}.${getExtensionFileType(targetBrowser)}`,
|
destination: `${path.join(
|
||||||
|
destPath,
|
||||||
|
targetBrowser
|
||||||
|
)}.${getExtensionFileType(targetBrowser)}`,
|
||||||
options: { zlib: { level: 6 } },
|
options: { zlib: { level: 6 } },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user