From 72c884dccd3ab74e60d065ad10c66422612e92c8 Mon Sep 17 00:00:00 2001 From: Fergal Moran Date: Wed, 15 Jan 2020 21:36:47 +0000 Subject: [PATCH] Initial commit --- .editorconfig | 12 +++ .gitattributes | 2 + .github/funding.yml | 1 + .gitignore | 3 + .travis.yml | 15 +++ media/previewer.png | Bin 0 -> 8507 bytes package.json | 53 ++++++++++ readme.md | 204 ++++++++++++++++++++++++++++++++++++++ source/background.js | 2 + source/icon.png | Bin 0 -> 1165 bytes source/manifest.json | 31 ++++++ source/options-storage.js | 13 +++ source/options.css | 69 +++++++++++++ source/options.html | 33 ++++++ source/options.js | 22 ++++ webpack.config.js | 44 ++++++++ 16 files changed, 504 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .github/funding.yml create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 media/previewer.png create mode 100644 package.json create mode 100644 readme.md create mode 100644 source/background.js create mode 100644 source/icon.png create mode 100644 source/manifest.json create mode 100644 source/options-storage.js create mode 100644 source/options.css create mode 100644 source/options.html create mode 100644 source/options.js create mode 100644 webpack.config.js diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1c6314a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +root = true + +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7fc4bae --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto eol=lf +*.ai binary diff --git a/.github/funding.yml b/.github/funding.yml new file mode 100644 index 0000000..fc010ad --- /dev/null +++ b/.github/funding.yml @@ -0,0 +1 @@ +custom: https://paypal.me/bytemode diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b23503d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +node_modules +yarn.lock +distribution diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..1a5d255 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: node_js +node_js: + - stable +env: + # Extension ID assigned by the Chrome Web Store + - EXTENSION_ID='000000000000000000000000000000000' +deploy: + - provider: script + skip_cleanup: true + script: npm run release + on: + # On cron jobs https://docs.travis-ci.com/user/cron-jobs/ + # When clicking "Trigger build" https://blog.travis-ci.com/2017-08-24-trigger-custom-build + branch: master + condition: (($TRAVIS_EVENT_TYPE = api) || ($TRAVIS_EVENT_TYPE = cron && $(git rev-list --since=yesterday HEAD))) diff --git a/media/previewer.png b/media/previewer.png new file mode 100644 index 0000000000000000000000000000000000000000..d89df0d9fe3d7bab745f00f9e01ec47cf05bafc4 GIT binary patch literal 8507 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 literal 0 HcmV?d00001 diff --git a/package.json b/package.json new file mode 100644 index 0000000..e9968fd --- /dev/null +++ b/package.json @@ -0,0 +1,53 @@ +{ + "private": true, + "scripts": { + "lint": "run-p lint:*", + "lint:js": "xo", + "lint:css": "stylelint source/**/*.css", + "lint-fix": "run-p 'lint:* -- --fix'", + "test": "run-s lint:* build", + "build": "webpack --mode=production", + "watch": "webpack --mode=development --watch", + "prerelease:version": "VERSION=$(utc-version); echo $VERSION; dot-json distribution/manifest.json version $VERSION", + "prerelease:source-url": "if [ ! -z \"${TRAVIS_REPO_SLUG}\" ]; then echo https://github.com/$TRAVIS_REPO_SLUG/tree/\"${TRAVIS_TAG:-$TRAVIS_COMMIT}\" > distribution/SOURCE_URL; fi", + "release": "npm-run-all build prerelease:* release:*", + "release:cws": "webstore upload --source=distribution --auto-publish", + "release:amo": "web-ext-submit --source-dir distribution" + }, + "devDependencies": { + "chrome-webstore-upload-cli": "^1.2.0", + "copy-webpack-plugin": "^5.0.3", + "dot-json": "^1.1.0", + "eslint": "^6.1.0", + "eslint-config-xo": "^0.26.0", + "npm-run-all": "^4.1.5", + "size-plugin": "^1.2.0", + "stylelint": "^10.1.0", + "stylelint-config-xo": "^0.15.0", + "terser-webpack-plugin": "^1.3.0", + "utc-version": "^2.0.1", + "web-ext": "^3.1.1", + "web-ext-submit": "^3.1.1", + "webpack": "^4.36.1", + "webpack-cli": "^3.3.6", + "xo": "^0.24.0" + }, + "dependencies": { + "webext-options-sync": "^0.21.2", + "webextension-polyfill": "^0.4.0" + }, + "xo": { + "envs": [ + "browser" + ], + "ignores": [ + "distribution" + ], + "globals": [ + "browser" + ] + }, + "stylelint": { + "extends": "stylelint-config-xo" + } +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..d65d0f5 --- /dev/null +++ b/readme.md @@ -0,0 +1,204 @@ +# browser-extension-template + +[link-webext-polyfill]: https://github.com/mozilla/webextension-polyfill +[link-rgh]: https://github.com/sindresorhus/refined-github +[link-ngh]: https://github.com/sindresorhus/notifier-for-github +[link-hfog]: https://github.com/sindresorhus/hide-files-on-github +[link-tsconfig]: https://github.com/sindresorhus/tsconfig +[link-xo-ts]: https://github.com/xojs/eslint-config-xo-typescript +[link-options-sync]: https://github.com/fregante/webext-options-sync +[link-cws-keys]: https://github.com/DrewML/chrome-webstore-upload/blob/master/How%20to%20generate%20Google%20API%20keys.md +[link-amo-keys]: https://addons.mozilla.org/en-US/developers/addon/api/key + +> Barebones boilerplate with webpack, options handler and auto-publishing. + +![Sample extension output](media/previewer.png) + +## Features + +- Use modern Promise-based `browser.*` APIs [webextension-polyfill][link-webext-polyfill]. +- [Auto-syncing options](#auto-syncing-options). +- [Auto-publishing](#publishing) with auto-versioning and support for manual releases. +- [Extensive configuration documentation](#configuration). + +This extension template is heavily inspired by [refined-github][link-rgh], [notifier-for-github][link-ngh], and [hide-files-on-github][link-hfog] browser extensions. You can always refer to these browser extensions' source code if you find anything confusing on how to create a new extension. + +## How to use this template + +Click [Use this template](https://github.com/notlmn/browser-extension-template/generate) and make a copy of your own. 😉 + +## Configuration + +The extension doesn't target any specific ECMAScript environment or provide any transpiling by default. The extensions output will be the same ECMAScript you write. This allows us to always target the latest browser version, which is a good practice you should be following. + +### Webpack + +#### Transpiling using Babel + +The template bakes in a pretty basic webpack config, with no transpiling. To setup transpiling using Babel follow the following configuration steps. + +1. Install Babel packages and respective loader for webpack. + + ``` sh + npm i --save-dev @babel/core @babel/preset-env babel-loader + ``` +1. In `webpack.config.js`, add the following rule to process JS files. + + ``` js + module: { + rules: [ + { + test: /\.js$/, + exclude: /node_modules/, + loader: 'babel-loader' + } + ] + } + ``` +1. Target respective browsers using `.babelrc`. + + ``` json + { + "presets": [ + ["@babel/preset-env", { + "targets": { + "chrome": "74", + "firefox": "67" + } + }] + ] + } + ``` + +#### Extracting CSS + +If you will be writing any code that will be importing CSS files from JS files, then you will be needing `mini-css-extract-plugin` to extract this imported CSS into its own file. + +1. Install the webpack plugin. + + ``` sh + npm i --save-dev mini-css-extract-plugin + ``` +1. Modify the webpack config as mentioned to let this plugin handle CSS imports. + + ``` js + // Import plugin + const MiniCssExtractPlugin = require('mini-css-extract-plugin'); + + // Under `module.rules` + { + test: /\.css$/, + use: [ + MiniCssExtractPlugin.loader, + 'css-loader' + ] + } + + // Under `plugins` + new MiniCssExtractPlugin({ + filename: 'content.css' + }) + ``` + +#### TypeScript + +TypeScript and Babel configs conflict each other, so you can only use one of these configuration types at any point. + +1. Install TypeScript and respective loader for webpack + + ``` sh + npm i --save-dev typescript ts-loader @types/firefox-webext-browser + ``` +1. Use the following webpack rule in the config file. + + ``` js + { + test: /\.(js|ts|tsx)$/, + loader: 'ts-loader', + exclude: /node_modules/ + }, + ``` + +1. Use the following as `tsconfig.json`, uses [sindresorhus/tsconfig][link-tsconfig] (install it as dependecy before using). + + ``` json + { + "extends": "@sindresorhus/tsconfig", + "compilerOptions": { + "target": "esnext", + "declaration": false + }, + "include": [ + "source" + ] + } + ``` + +TypeScript requires additional configuration depending on how you set it up, like [linting][link-xo-ts]. + +### Auto-syncing options + +Options are managed by [fregante/webext-options-sync][link-options-sync], which auto-saves and auto-restores the options form, applies defaults and runs migrations. + +### Publishing + +It's possible to publish to both the Chrome Web Store and Mozilla Addons at once by creating these ENV variables: + +1. `CLIENT_ID`, `CLIENT_SECRET`, and `REFRESH_TOKEN` from [Google APIs][link-cws-keys]. +1. `WEB_EXT_API_KEY`, and `WEB_EXT_API_SECRET` from [AMO][link-amo-keys]. + +And then running: + +``` sh +npm run release +``` + +This will: + +1. Build the extension +1. Create a version number based on the current UTC time, like [`19.6.16.428`](https://github.com/LinusU/utc-version#utc-version) and sets it in the manifest.json +1. Deploy it to both stores + +#### Auto-publishing + +Thanks to the included [Travis file](.travis.yml), if you set up those ENVs on Travis, the deployment will automatically happen: + +- when clicking ["Trigger build"](https://blog.travis-ci.com/2017-08-24-trigger-custom-build) +- every day, if you configure the [Cron Job](https://docs.travis-ci.com/user/cron-jobs/) (but only if there are any new commits in the last day) + +#### Auto-publishing on tags + +If you prefer picking your versions and publishing on demand, replace the deployment in [Travis file](.travis.yml) with: + +``` yml + - provider: script + skip_cleanup: true + script: npm run release + on: + tags: true +``` + +And then replace the `prerelease:version` script in [package.json](package.json) with: + +``` json +"prerelease:version": "dot-json distribution/manifest.json version $TRAVIS_TAG", +``` + +And your extension will be published when creating a git tag, using the tag itself as version for the extension. + +### License + +This browser extension template is released under [MIT](#license) and mentioned below. There is no `license` file included in here, but when you clone this template, you should include your own license file for the specific license you choose to use. + +## Credits + +Extension icon made by [Freepik](https://www.freepik.com) from [www.flaticon.com](https://www.flaticon.com) is licensed by [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0). + +## Extensions created using this template + +- [notlmn/copy-as-markdown](https://github.com/notlmn/copy-as-markdown) - Browser extension to copy hyperlinks, images, and selected text as Markdown. + +## License + +[![CC0](https://mirrors.creativecommons.org/presskit/buttons/88x31/svg/cc-zero.svg)](https://creativecommons.org/publicdomain/zero/1.0/) + diff --git a/source/background.js b/source/background.js new file mode 100644 index 0000000..bda33f9 --- /dev/null +++ b/source/background.js @@ -0,0 +1,2 @@ +// eslint-disable-next-line import/no-unassigned-import +import './options-storage'; diff --git a/source/icon.png b/source/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a4905069f9a21264dfda3d2064565c720a5650ef GIT binary patch literal 1165 zcmV;81akX{P)C0005hP)t-s00030 zT$FX+*2%2NjXVMIZRACOiVgW zO*>RnJzHBoN=!apUOr!5KuSzON=!j%XhCdiLTzkAad1USPDV>lMtFBdetbuLdq;qN zNri(+h=ogxic5`)O_q~SnwL+Sm{4J3QKh0%rlVH1u~xORSGKZPYHe7)x?07+Tgby* z(9B-Y%wN^eU)R!K*wbLw(_q=uVcFDT*wSU#&1cxkXV}YVPFrYBTx!?HYffBj*TZ$y zxOUaHc-6FjQDlHoWr0v+h0~&j)1imbpoi0+iP4*h(wn5tc%{yFr_FS!&2g&DZ>!92 ztjun>R(icxd%ahDy~$R-SA4_CPQ=Jf##n#HSb)e_fX!Hf&c{H|$3D`>I@Vf-*II_z z#V^`ghuXz2+ggX)#Vy;#F5Fs(+{7&FTaD{njqF^G^uY}JzyJP{a%#)UX}f* zB>kx&{jV7PuowNY7X7jl{j(GOxC{Ng1O2@O{l5VIc5wcHVE%$%{)trni%e3g9>oGewq00-Sjw2MZVw8Vhh3zyJm?fB_6(00S71G9aPp zPtPZxA^|^|dNGOxX#MdW7@()(V1S-}1P18OV_<-Og9dy-1M~etjRs7j0dX{7 z7!3Fj0|Umv`@s9hV8DdIk5RNQ61gAsH~(wQ7@(~wC}#>bUH38n+cQ(=f$l@{SG7G} z@Bc*1)QRYFkxXdmMNjYF_!DD?(o1>rxALx#%U;g*Dn2}B?pWSkB$HZx*Xn;ky>wM; z6VN7!Zde2yr2xn50ir<)ux7{_pih!Lum`Q%t!E(}1udV*mpfz<~b|aDoOLw+1*u0}fjQ92lhL4<57zQ1>Xn z9c2%2fdZVf2x#bc&+l)r2vFzUfV0Xbp!#O={9Dz=0EL@(mRG7jRM(sI1lB1-fP(G& zl$UC*CC59>DnEb~mCAfR0D&@v z1#DDcz#cH5K!E{k(SS{8KrtGy0S#D%1_bt^_kmJ0ps)%IklWCJzz#4#F4+YJ$iUVr zEI`U-r4?Af%vD&qu6WCA_5mLL3mCuv1~7mD3}65Q{w+X077!8(uz+llu^0&mr3;ZU fKOY4MWv7epzkc)UpBDlk00000NkvXXu0mjfOI<8g literal 0 HcmV?d00001 diff --git a/source/manifest.json b/source/manifest.json new file mode 100644 index 0000000..94a6273 --- /dev/null +++ b/source/manifest.json @@ -0,0 +1,31 @@ +{ + "name": "Awesome Extension", + "version": "0.0.0", + "description": "An awesome new browser extension", + "homepage_url": "https://github.com/awesome-templates/browser-extension-template", + "manifest_version": 2, + "minimum_chrome_version": "74", + "applications": { + "gecko": { + "id": "your-extension-name@your-domain.com", + "strict_min_version": "67.0" + } + }, + "icons": { + "128": "icon.png" + }, + "permissions": [ + "storage" + ], + "options_ui": { + "chrome_style": true, + "page": "options.html" + }, + "background": { + "persistent": false, + "scripts": [ + "browser-polyfill.min.js", + "background.js" + ] + } +} diff --git a/source/options-storage.js b/source/options-storage.js new file mode 100644 index 0000000..41d8a12 --- /dev/null +++ b/source/options-storage.js @@ -0,0 +1,13 @@ +import OptionsSync from 'webext-options-sync'; + +export default new OptionsSync({ + defaults: { + colorRed: 244, + colorGreen: 67, + colorBlue: 54 + }, + migrations: [ + OptionsSync.migrations.removeUnused + ], + logging: true +}); diff --git a/source/options.css b/source/options.css new file mode 100644 index 0000000..dd0eaee --- /dev/null +++ b/source/options.css @@ -0,0 +1,69 @@ +html { + min-width: 550px; + overflow-x: hidden; /* Required to hide horizontal scroll on Firefox */ +} + +/* For use with screen readers */ +.sr-only { + display: none; +} + + +/* Hide spinbox for number inputs */ +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +input[type='number'] { + -moz-appearance: textfield; +} + + +input[type='number'], +input[type='text'] { + padding: 0.25rem 0.375rem; +} + + +.color-picker { + display: flex; +} + +.color-inputs { + flex: 1; +} + +.color-input { + display: flex; + padding: 0.25rem; + align-items: center; +} + +.color-input input[type='range'] { + flex: 1; + margin: 0 0.5rem; +} + +.color-input input[type='number'] { + width: calc(3ch + 1rem); +} + +.color-output { + width: 86px; + height: 86px; + margin: 0.5rem; +} + + +/* Firefox only */ +.only-firefox { + display: none; +} + +@-moz-document url-prefix('') { + .only-firefox { + display: block; + } +} diff --git a/source/options.html b/source/options.html new file mode 100644 index 0000000..3d15cd1 --- /dev/null +++ b/source/options.html @@ -0,0 +1,33 @@ + + +Options + + + +
+

Color Previewer

+
+
+ + + +
+
+
+
+
+ + + diff --git a/source/options.js b/source/options.js new file mode 100644 index 0000000..360454f --- /dev/null +++ b/source/options.js @@ -0,0 +1,22 @@ +import optionsStorage from './options-storage'; + +optionsStorage.syncForm('#options-form'); + +const rangeInputs = [...document.querySelectorAll('input[type="range"][name^="color"]')]; +const numberInputs = [...document.querySelectorAll('input[type="number"][name^="color"]')]; +const output = document.querySelector('.color-output'); + +function updateColor() { + output.style.backgroundColor = `rgb(${rangeInputs[0].value}, ${rangeInputs[1].value}, ${rangeInputs[2].value})`; +} + +function updateInputField(event) { + numberInputs[rangeInputs.indexOf(event.currentTarget)].value = event.currentTarget.value; +} + +for (const input of rangeInputs) { + input.addEventListener('input', updateColor); + input.addEventListener('input', updateInputField); +} + +window.addEventListener('load', updateColor); diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..9e11dd1 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,44 @@ +const path = require('path'); +const SizePlugin = require('size-plugin'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const TerserPlugin = require('terser-webpack-plugin'); + +module.exports = { + devtool: 'sourcemap', + stats: 'errors-only', + entry: { + background: './source/background', + options: './source/options' + }, + output: { + path: path.join(__dirname, 'distribution'), + filename: '[name].js' + }, + plugins: [ + new SizePlugin(), + new CopyWebpackPlugin([ + { + from: '**/*', + context: 'source', + ignore: '*.js' + }, + { + from: 'node_modules/webextension-polyfill/dist/browser-polyfill.min.js' + } + ]) + ], + optimization: { + minimizer: [ + new TerserPlugin({ + terserOptions: { + mangle: false, + compress: false, + output: { + beautify: true, + indent_level: 2 // eslint-disable-line camelcase + } + } + }) + ] + } +};