diff --git a/react-es6-popup/.babelrc b/react-es6-popup/.babelrc new file mode 100644 index 0000000..ffd1d11 --- /dev/null +++ b/react-es6-popup/.babelrc @@ -0,0 +1,11 @@ +{ + "presets": [ + "es2015", + "stage-2", + "react" + ], + "plugins": [ + "transform-class-properties", + "transform-es2015-modules-commonjs" + ] +} diff --git a/react-es6-popup/.gitignore b/react-es6-popup/.gitignore new file mode 100644 index 0000000..20ccaa9 --- /dev/null +++ b/react-es6-popup/.gitignore @@ -0,0 +1,5 @@ +# Ignore build artifacts and other files. +.DS_Store +yarn.lock +extension/dist +node_modules diff --git a/react-es6-popup/.npmrc b/react-es6-popup/.npmrc new file mode 100644 index 0000000..a00908d --- /dev/null +++ b/react-es6-popup/.npmrc @@ -0,0 +1 @@ +save-prefix='' diff --git a/react-es6-popup/README.md b/react-es6-popup/README.md new file mode 100644 index 0000000..5fa69cf --- /dev/null +++ b/react-es6-popup/README.md @@ -0,0 +1,54 @@ +# React / ES6 Popup Example + +## What it does + +This is an example of creating a browser action +[popup](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Add_a_button_to_the_toolbar#Adding_a_popup) +UI in [React][react] and [ES6](http://es6-features.org/) JavaScript. + +## What it shows + +* How to bundle [React][react] and any other [NodeJS][nodejs] module into an + extension. +* How to transpile code that is not supported natively in + a browser such as + [import / export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) + syntax and [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html). +* How to continuously build code as you edit files. +* How to customize [web-ext][web-ext] for your extension's specific needs. +* How to structure your code in reusable ES6 modules. + +## Usage + +First, you need to change into the example subdirectory and install all +[NodeJS][nodejs] dependencies with [npm](http://npmjs.com/) or +[yarn](https://yarnpkg.com/): + + npm install + +Start the continuous build process to transpile the code into something that +can run in Firefox or Chrome: + + npm run build + +This creates a WebExtension in the `extension` subdirectory. +Any time you edit a file, it will be rebuilt automatically. + +In another shell window, run the extension in Firefox using a wrapper +around [web-ext][web-ext]: + + npm start + +Any time you edit a file, [web-ext][web-ext] will reload the extension +in Firefox. To see the popup, click the watermelon icon from the browser bar. +Here is what it looks like: + +![popup screenshot](screenshots/popup.png "React popup screenshot") + +[react]: https://facebook.github.io/react/ +[nodejs]: https://nodejs.org/en/ +[web-ext]: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Getting_started_with_web-ext + +## Icons + +The icon for this extension is provided by [icons8](https://icons8.com/). diff --git a/react-es6-popup/extension/images/Watermelon-48.png b/react-es6-popup/extension/images/Watermelon-48.png new file mode 100644 index 0000000..2821b3f Binary files /dev/null and b/react-es6-popup/extension/images/Watermelon-48.png differ diff --git a/react-es6-popup/extension/images/Watermelon-96.png b/react-es6-popup/extension/images/Watermelon-96.png new file mode 100644 index 0000000..0b4f4f1 Binary files /dev/null and b/react-es6-popup/extension/images/Watermelon-96.png differ diff --git a/react-es6-popup/extension/manifest.json b/react-es6-popup/extension/manifest.json new file mode 100755 index 0000000..5126bdd --- /dev/null +++ b/react-es6-popup/extension/manifest.json @@ -0,0 +1,17 @@ +{ + "manifest_version": 2, + "name": "react-es6-popup-example", + "version": "1.0", + + "browser_action": { + "browser_style": true, + "default_icon": { + "48": "images/Watermelon-48.png", + "96": "images/Watermelon-96.png" + }, + "default_title": "React Example", + "default_popup": "popup.html" + }, + + "permissions": ["activeTab"] +} diff --git a/react-es6-popup/extension/popup.css b/react-es6-popup/extension/popup.css new file mode 100755 index 0000000..1b048c9 --- /dev/null +++ b/react-es6-popup/extension/popup.css @@ -0,0 +1,8 @@ +body { + width: 400px; + padding: 1em; +} + +h1, h2 { + border-bottom: 1px solid; +} diff --git a/react-es6-popup/extension/popup.html b/react-es6-popup/extension/popup.html new file mode 100755 index 0000000..a005aa0 --- /dev/null +++ b/react-es6-popup/extension/popup.html @@ -0,0 +1,11 @@ + + + + + + + +
+ + + diff --git a/react-es6-popup/package.json b/react-es6-popup/package.json new file mode 100644 index 0000000..e4930ae --- /dev/null +++ b/react-es6-popup/package.json @@ -0,0 +1,25 @@ +{ + "name": "react-es6-popup-example", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "webpack -w -v --display-error-details --progress --colors", + "start": "web-ext run -s extension/" + }, + "author": "", + "license": "MPL-2.0", + "devDependencies": { + "babel-core": "6.20.0", + "babel-loader": "6.2.9", + "babel-plugin-transform-class-properties": "6.19.0", + "babel-plugin-transform-object-rest-spread": "6.20.2", + "babel-preset-es2015": "6.18.0", + "babel-preset-react": "6.16.0", + "babel-preset-stage-2": "6.18.0", + "react": "15.4.1", + "react-dom": "15.4.1", + "web-ext": "1.6.0", + "webpack": "1.14.0" + } +} diff --git a/react-es6-popup/screenshots/popup.png b/react-es6-popup/screenshots/popup.png new file mode 100644 index 0000000..933d435 Binary files /dev/null and b/react-es6-popup/screenshots/popup.png differ diff --git a/react-es6-popup/src/nested-component.js b/react-es6-popup/src/nested-component.js new file mode 100644 index 0000000..1ca1496 --- /dev/null +++ b/react-es6-popup/src/nested-component.js @@ -0,0 +1,15 @@ +import React from 'react'; + +export default class Nested extends React.Component { + render() { + return ( +
+

Nested Component

+

+ This is an example of a nested component that was imported via + import / export syntax. +

+
+ ); + } +} diff --git a/react-es6-popup/src/popup.js b/react-es6-popup/src/popup.js new file mode 100755 index 0000000..045a618 --- /dev/null +++ b/react-es6-popup/src/popup.js @@ -0,0 +1,36 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import Nested from './nested-component'; + +class Popup extends React.Component { + constructor(props) { + super(props); + this.state = {activeTab: null}; + } + + componentDidMount() { + // Get the active tab and store it in component state. + chrome.tabs.query({active: true}, tabs => { + this.setState({activeTab: tabs[0]}); + }); + } + + render() { + const {activeTab} = this.state; + return ( +
+

React Component

+

+ This is an example of a popup UI in React. +

+

+ Active tab: {activeTab ? activeTab.url : '[waiting for result]'} +

+ +
+ ); + } +} + +ReactDOM.render(, document.getElementById('app')); diff --git a/react-es6-popup/webpack.config.js b/react-es6-popup/webpack.config.js new file mode 100644 index 0000000..c6decf7 --- /dev/null +++ b/react-es6-popup/webpack.config.js @@ -0,0 +1,48 @@ +const path = require('path'); +const webpack = require('webpack'); + +module.exports = { + entry: { + // Each entry in here would declare a file that needs to be transpiled + // and included in the extension source. + // For example, you could add a background script like: + // background: './src/background.js', + popup: './src/popup.js', + }, + output: { + // This copies each source entry into the extension dist folder named + // after its entry config key. + path: 'extension/dist', + filename: '[name].js', + }, + module: { + // This transpiles all code (except for third party modules) using Babel. + loaders: [{ + exclude: /node_modules/, + test: /\.js$/, + // Babel options are in .babelrc + loaders: ['babel'], + }], + }, + resolve: { + // This allows you to import modules just like you would in a NodeJS app. + extensions: ['', '.js', '.jsx'], + root: [ + path.resolve(__dirname), + ], + modulesDirectories: [ + 'src', + 'node_modules', + ], + }, + plugins: [ + // Since some NodeJS modules expect to be running in Node, it is helpful + // to set this environment var to avoid reference errors. + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('production'), + }), + ], + // This will expose source map files so that errors will point to your + // original source files instead of the transpiled files. + devtool: 'sourcemap', +};