Skip to content

Commit 0c9e25c

Browse files
committed
cross-browser boilerplate
1 parent 08a9d20 commit 0c9e25c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+1303
-394
lines changed

.github/FUNDING.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# These are supported funding model platforms
2+
3+
github: fxnoob
4+
patreon: fxnoob
5+
open_collective: # Replace with a single Open Collective username
6+
ko_fi: # Replace with a single Ko-fi username
7+
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8+
custom: # Replace with a single custom sponsorship URL

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ babel
44
55
dist/
66
out/
7+
dist.zip

README.md

Lines changed: 84 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,108 @@
1-
# A Chrome extension boilerplate.
1+
# A Browser(Chrome/Edge/Firefox/Brave) extension boilerplate.
2+
3+
## Prerequisites
4+
5+
- yarn v1.17.3
6+
- node v12.3.1
7+
8+
## Pre-configurations
9+
10+
> * Replace `Constants.appConfig.key` in `constants.js` with your chrome extension's key obtained from chrome developer extension dashboard.
11+
> * Set `GECKO_ID` in `constants.js` and Set other configurations in `constants.js` when required.
12+
> * Set extension next version in `package.json` version before building.
13+
> * Generate locale for key `appName` and `appDescription` for extension's name and description. See `yarn generate:locale`.
214
315
## Basic Usage
416

17+
### Locale generate/Delete
18+
19+
Generate locale
20+
````
21+
yarn generate:locale
22+
````
23+
24+
Delete locale
25+
````
26+
yarn delete:locale
27+
````
28+
29+
### Build
30+
31+
#### For Local Development
32+
33+
#### For Chromium Development Build
34+
35+
```
36+
yarn
37+
yarn dev:chromium
38+
```
39+
40+
#### For Firefox Development Build
41+
542
```
6-
yarn
7-
yarn dev // create development build
8-
yarn build // create production build
43+
yarn
44+
yarn dev:firefox
945
```
1046

47+
#### For Production Release
48+
49+
> Note: Before creating production build. Set version in package.json's version. that will be extension's build version.
50+
51+
#### For Chromium Build
52+
53+
```
54+
yarn
55+
yarn build:chromium
56+
```
57+
58+
#### For Firefox Build
59+
60+
```
61+
yarn
62+
yarn build:firefox
63+
```
64+
65+
66+
1167
## features:
1268

13-
> 1. Support for ES7 ( with Babel and polyfill)
14-
> 2. popup page with reactjs and material ui framework
15-
> 3. Content script with reactjs and material ui framework
16-
> 4. Bundling (webpack)
69+
> 1. Support for ESNEXT ( with Babel and polyfill).
70+
> 2. Popup page with reactjs and material ui framework.
71+
> 3. Content script with reactjs and material ui framework.
72+
> 5. Option Page with reactjs and material ui framework + tailwind css.
73+
> 5. Bundling (webpack).
74+
> 6. Cross-browser configurations.
75+
> 7. Generate multiple-language (Auto-translations) locales from english locales. See `yarn generate:locale` and `yarn delete:locale`.
76+
> 8. Some (useful) services e.g. DbService, messagePassing, chromeService and helper functions(helpers).
77+
> 9. Some (useful) react components e.g. FrameMUI.js (To mount react mui component in iframe in content script).
78+
> 10. Locale translation using unofficial google translate API (Free version).
1779
1880
## directory structure
1981

2082
> - `src/` is root directory for a chrome extension. it includes `manifest.json` file and other static stuff.
2183
2284
> - `src/background.js` is main background js file for the chrome extension.
2385
86+
> - `src/components` is the directory which includes react js components.
87+
2488
> - `src/popup-page` is the directory which includes react js setup for popup page.
2589
26-
> - `src/content-scripts` is the directory directory which includes react js setup for content script.
90+
> - `src/option-page` is the directory which includes react js setup for option pages.
91+
92+
> - `src/content-scripts` is the directory which includes react js setup for content script.
2793
2894
> - `src/services` is the directory for services that can be written in es6,es7 or es8...
2995
3096
## How to extend ?
3197

32-
> - Write chrome extension's background scripts code in `src/background.js`
98+
> - Write extension's background scripts code in `src/background.js`
99+
100+
> - Write extension's react components in `src/components/` directory.
101+
102+
> - Write extension's popup page codes in `src/popup-page/` directory.
103+
104+
> - Write extension's option page codes in `src/option-page` directory.
33105
34-
> - Write chrome extension's popup page codes in `src/popup-page` Reactjs directory system.
106+
> - Write extension's content scripts codes in `src/content-scripts` directory.
35107
36-
> - Write chrome extension's content scripts codes in `src/content-scripts` Reactjs directory system.
108+
> - Write extension's services codes in `src/services` directory.

chromium.webpack.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const baseConfig = require("./webpack.config");
2+
module.exports = (env, options) => {
3+
return baseConfig(env, {
4+
...options, // app specific configurations
5+
browser: "chromium",
6+
});
7+
};

constants.js

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,40 @@
1+
const { generateGuid } = require("./src/services/guid");
12
const constants = {
23
appConfig: {
3-
appName: "extension name",
4+
appName: "EXTENSION_NAME",
5+
urls: {
6+
chrome:
7+
"CHROME_STORE_URL",
8+
firefox: "FIREFOX_STORE_URL",
9+
edge:
10+
"EDGE_STORE_URL",
11+
},
12+
// put extension key here if required which would only be used in development mode
413
key:
5-
"-----BEGIN PUBLIC KEY-----\n" +
6-
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3VymTQvpTgWpVbYeveQV\n" +
7-
"I2ZuyKZtHtzDqIWu4Og/ZjOEbu6eXPzvX57BmMv0sX79Y0EDRHkbQAgtWjgilCTE\n" +
8-
"uWqxCOLpLpkYs9Dz/iXymqbIaM6IbLZEp513uKMSTknU9V5eWFuNeOU8Ps/6rr35\n" +
9-
"chBpbVxeWawy5jLak03n5jFRCnOtkzoU9gkbbTQRykV2dfp+KP0UYn7Vox/17fCH\n" +
10-
"CHPG5oA/DvH60iokIhoUXe+5SCIFcdsJE/a7gvH7YGbDkC6+ENpmUK0dEIEJSHAh\n" +
11-
"vyLwCl4pmiIC/crpbLxlV5SPfAN+P3tiAUlS0M5U2f0Nf6AFayvazJslHKTarU3K\n" +
12-
"qQIDAQAB\n" +
13-
"-----END PUBLIC KEY-----\n"
14-
}
14+
// eslint-disable-next-line max-len
15+
"-----BEGIN PUBLIC KEY-----\nMssIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhnjCHD79hDbWfqjnP9SW\nN0AXmXHh5eVk2D0oMILadmj/2uRQm/jNpnlvjVHY+899gdYRH/k7v4f+qF6gV3Yh\nwb/2PnW9PEo2VksgiixSesccvcwRXEJSngtxNWOARYSOTqTCCum9rjFVPZL+voh7\ndUsTN45D+RBLQORYbu5NtSM6RcGhUbYvhAosKwo+lsOAjM5niQDLJi//dZ9R32tc\n6tht4XrP59CTWBo8JCpIcHT6edN2HQ2vRiO5CHVb2jfT1hrO82WZ9LWsErzo/gCr\nXyIvnnXjg1wif7++WTi5mQl05Ohv3vKazNLeFpl/2XxvJ1xw4Pfh7m2qMaBJd7ll\n3QIDAQAB\n-----END PUBLIC KEY-----",
16+
},
17+
contentScript: {
18+
mountId: generateGuid(),
19+
},
20+
browser: {
21+
firefox: {
22+
manifest: {
23+
browser_specific_settings: {
24+
gecko: {
25+
id: "GECKO_ID",
26+
strict_min_version: "42.0",
27+
},
28+
},
29+
},
30+
},
31+
},
32+
support: {
33+
donate: "https://www.patreon.com/fxnoob",
34+
howToVideoLink: "TUTORIAL_LINK",
35+
uninstallFeedbackForm: "HTTPS://FEEDBACK_FORM_LINK",
36+
},
1537
};
1638

1739
module.exports = constants;
40+

firefox.webpack.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const baseConfig = require("./webpack.config");
2+
module.exports = (env, options) => {
3+
return baseConfig(env, {
4+
...options, // app specific configurations
5+
browser: "firefox",
6+
});
7+
};

package.json

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,30 @@
11
{
22
"name": "chrome-extension-boilerplate",
3-
"version": "1.0.0",
3+
"version": "0.0.1",
44
"description": "",
55
"main": "index.js",
66
"homepage": "https://fxnoob.github.io/chrome-extension-boilerplate",
77
"scripts": {
8-
"build:css": "tailwindcss build src/styles/style.css -o dist/style.css",
9-
"watch:css": "yarn build:css && chokidar 'src/styles/*.css' -c 'yarn build:css'",
10-
"watch:js": "webpack --watch --config webpack.config.js --mode=development",
11-
"build:js": "webpack --config webpack.config.js --mode=production",
8+
"build:tailwind": "tailwindcss build src/styles/style.css -o dist/style.css",
9+
"watch:tailwind": "chokidar 'src/styles/*.css' -c 'yarn build:tailwind'",
10+
"prestart": "yarn build:tailwind",
11+
"prebuild": "yarn rm && yarn build:tailwind",
1212
"rm": "rm -rf dist/",
13-
"start": "yarn dev",
14-
"dev": "concurrently --kill-others 'yarn watch:css' 'yarn watch:js'",
15-
"build": "yarn rm && concurrently 'yarn build:css' 'yarn build:js'",
13+
"rm:zip": "rm dist.zip",
14+
"dev:chromium": "yarn build:tailwind && webpack --watch --progress --colors --config chromium.webpack.js --mode=development",
15+
"dev:firefox": "yarn build:tailwind && webpack --watch --progress --colors --config firefox.webpack.js --mode=development",
16+
"build:chromium": "yarn build:tailwind && webpack --progress --colors --config chromium.webpack.js --mode=production",
17+
"build:firefox": "yarn build:tailwind && webpack --progress --colors --config firefox.webpack.js --mode=production",
1618
"jsdoc": "jsdoc src -r",
1719
"deploy_jsdoc": "yarn jsdoc && gh-pages -d out",
18-
"test": "yarn build"
20+
"zip": "zip -r dist.zip dist/*",
21+
"test": "yarn build:chromium && yarn build:firefox",
22+
"generate:locale": "node scripts/generate-locale",
23+
"delete:locale": "node scripts/delete-locale"
1924
},
2025
"husky": {
2126
"hooks": {
22-
"pre-commit": "yarn build"
27+
"pre-commit": "yarn test && yarn rm"
2328
}
2429
},
2530
"keywords": [],
@@ -51,23 +56,27 @@
5156
"husky": "^3.0.9",
5257
"image-webpack-loader": "^5.0.0",
5358
"jsdoc": "^3.6.3",
54-
"prettier": "1.18.2",
59+
"prettier": "^2.2.1",
5560
"pretty-quick": "^2.0.0",
5661
"react-hot-loader": "^4.12.10",
5762
"style-loader": "^1.2.1",
5863
"webpack": "^4.39.1",
5964
"webpack-cli": "^3.3.6",
60-
"webpack-dev-server": "^3.7.2"
65+
"webpack-dev-server": "^3.7.2",
66+
"node-google-translate-skidz": "^1.1.2",
67+
"zx": "^1.0.2",
68+
"tailwindcss": "^1.8.3",
69+
"@tailwindcss/ui": "^0.5.0"
6170
},
6271
"dependencies": {
6372
"@babel/polyfill": "^7.4.4",
6473
"@babel/runtime": "^7.5.5",
6574
"@material-ui/core": "^4.3.3",
6675
"@material-ui/icons": "^4.2.1",
67-
"@tailwindcss/ui": "^0.5.0",
76+
"jss": "^10.6.0",
77+
"jss-rtl": "^0.3.0",
6878
"react": "^16.8.6",
6979
"react-dom": "^16.8.6",
70-
"react-frame-component": "^4.1.3",
71-
"tailwindcss": "^1.8.3"
80+
"react-frame-component": "5.0.0"
7281
}
7382
}

scripts/delete-locale

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#! /usr/bin/env node
2+
3+
require = require('esm')(module);
4+
require('./deleteLocale').cli(process.argv);

scripts/deleteLocale.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/* eslint-disable no-console */
2+
import path from "path";
3+
import chalk from "chalk/source";
4+
import arg from "arg";
5+
import inquirer from "inquirer";
6+
import { deleteLocales } from "./delete_locales";
7+
const jsonfile = require("jsonfile");
8+
const mainLocaleJsonFile = path.join(__dirname, "./locale_en.json");
9+
const localeJson = jsonfile.readFileSync(mainLocaleJsonFile);
10+
11+
function parseArgsIntoOptions(rawArgs) {
12+
const args = arg(
13+
{
14+
"--key": String,
15+
"--del": Boolean,
16+
},
17+
{
18+
argv: rawArgs.slice(2),
19+
}
20+
);
21+
return {
22+
key: args["--key"] || null,
23+
del: args["--del"] || null,
24+
};
25+
}
26+
function isNull(val) {
27+
return val == null;
28+
}
29+
async function promptForMissingOptions(options) {
30+
const validateInput = (propName) => (value) => {
31+
if (value == "") return `${propName} can't be Empty!`;
32+
else if (propName == "key") {
33+
if (!localeJson.hasOwnProperty(value)) {
34+
return "key does not exist!";
35+
} else {
36+
return true;
37+
}
38+
} else {
39+
return true;
40+
}
41+
};
42+
const questions = [];
43+
if (isNull(options.key)) {
44+
questions.push({
45+
type: "input",
46+
validate: validateInput("key"),
47+
name: "key",
48+
message: "type key name:",
49+
});
50+
}
51+
if (isNull(options.delete)) {
52+
questions.push({
53+
type: "confirm",
54+
name: "del",
55+
default: false,
56+
message: "do you really want to delete this locale?",
57+
});
58+
}
59+
const answers = await inquirer.prompt(questions);
60+
return {
61+
...options,
62+
key: options.key || answers.key,
63+
del: options.del || answers.del,
64+
};
65+
}
66+
async function updatelocales(options) {
67+
const { key } = options;
68+
/* delete key and update main en locale file */
69+
delete localeJson[key];
70+
jsonfile.writeFileSync(mainLocaleJsonFile, localeJson, {
71+
flag: "w",
72+
});
73+
/* update other locale files */
74+
deleteLocales([{ key: key }]);
75+
}
76+
export async function cli(args) {
77+
let options = parseArgsIntoOptions(args);
78+
options = await promptForMissingOptions(options);
79+
if (!options.del) return;
80+
// delete the key value from the json file and then update all locales
81+
await updatelocales(options);
82+
console.log(chalk.cyan(`locale key ${options.key} has been deleted!`));
83+
}

scripts/delete_locales.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* eslint-disable no-console */
2+
const jsonfile = require("jsonfile");
3+
const path = require("path");
4+
const { locales } = require("./translate");
5+
/**
6+
*
7+
* takes updated locale_en.json
8+
* delete provided locale keys from ../src/app/_locales/${locale}/messages.json
9+
*
10+
* */
11+
function deleteLocales(keys) {
12+
const targetDirRoot = path.join(__dirname, "../src/app/_locales");
13+
for (let i = 0; i < locales.length; i++) {
14+
const locale = locales[i];
15+
const oldJsonFilePath = path.join(
16+
targetDirRoot,
17+
`/${locale}/messages.json`
18+
);
19+
const oldJsonFile = jsonfile.readFileSync(oldJsonFilePath);
20+
for (let j = 0; j < keys.length; j++) {
21+
if (oldJsonFile[keys[j].key]) {
22+
delete oldJsonFile[keys[j].key];
23+
console.log("deleting key ->", keys[j].key);
24+
}
25+
}
26+
jsonfile.writeFileSync(oldJsonFilePath, oldJsonFile, { flag: "w" });
27+
}
28+
}
29+
export { deleteLocales };

0 commit comments

Comments
 (0)