44 | `;
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Alexander Schwartzberg
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Prerequisites
2 |
3 | Please answer the following questions for yourself before submitting an issue:
4 |
5 | - [ ] I am running the latest version
6 | - [ ] I checked the documentation and found no answer
7 | - [ ] I checked to make sure that this issue has not already been filed
8 | - [ ] I'm reporting the issue to the correct repository (for multi-repository projects)
9 |
10 | ## Context
11 |
12 | Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.
13 |
14 | ## Expected Behavior
15 |
16 | If relevant, please describe the behavior you are expecting
17 |
18 | ## Current Behavior
19 |
20 | If relevant, describe the current behavior
21 |
22 | ## Failure Information (for bugs)
23 |
24 | Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template.
25 |
26 | ### Steps to Reproduce
27 |
28 | Please provide detailed steps for reproducing the issue.
29 |
30 | 1. step 1
31 | 2. step 2
32 | 3. you get it...
33 |
34 | ### Failure Logs
35 |
36 | Please include any relevant log snippets or files here.
37 |
--------------------------------------------------------------------------------
/src/components/scroller/stories/Scroller.stories.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { Scroller } from "../component";
3 | import { ComponentMeta, ComponentStory } from "@storybook/react";
4 | import { within, userEvent } from "@storybook/testing-library";
5 | import { action } from "@storybook/addon-actions";
6 |
7 | // // // //
8 |
9 | export default {
10 | title: "Components/Scroller",
11 | component: Scroller,
12 | args: {
13 | onClickScrollTop: action("click-scroll-top"),
14 | onClickScrollBottom: action("click-scroll-bottom"),
15 | },
16 | } as ComponentMeta;
17 |
18 | const Template: ComponentStory = (args) => (
19 |
20 | );
21 |
22 | // // // //
23 |
24 | export const Render = Template.bind({});
25 |
26 | export const ScrollTop = Template.bind({});
27 | ScrollTop.play = async ({ canvasElement }) => {
28 | const canvas = within(canvasElement);
29 | await userEvent.click(canvas.getByTestId("scroll-to-top"));
30 | };
31 |
32 | export const ScrollBottom = Template.bind({});
33 | ScrollBottom.play = async ({ canvasElement }) => {
34 | const canvas = within(canvasElement);
35 | await userEvent.click(canvas.getByTestId("scroll-to-bottom"));
36 | };
37 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: '@typescript-eslint/parser', // Specifies the ESLint parser
3 | extends: [
4 | 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from @typescript-eslint/eslint-plugin
5 | 'plugin:react/recommended', // Uses the recommended rules from @eslint-plugin-react
6 | 'prettier/@typescript-eslint', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier
7 | 'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
8 | ],
9 | parserOptions: {
10 | ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
11 | sourceType: 'module', // Allows for the use of imports
12 | ecmaFeatures: {
13 | jsx: true, // Allows for the parsing of JSX
14 | },
15 | },
16 | rules: {
17 | // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
18 | // e.g. "@typescript-eslint/explicit-function-return-type": "off",
19 | },
20 | settings: {
21 | react: {
22 | version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use
23 | },
24 | },
25 | };
26 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Description
2 |
3 | Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
4 |
5 | Fixes # (issue)
6 |
7 | ## Type of change
8 |
9 | Please delete options that are not relevant.
10 |
11 | - [ ] Bug fix (non-breaking change which fixes an issue)
12 | - [ ] New feature (non-breaking change which adds functionality)
13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
14 | - [ ] This change requires a documentation update
15 |
16 | ## How Has This Been Tested?
17 |
18 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
19 |
20 | ## Checklist:
21 |
22 | - [ ] My code follows the style guidelines of this project
23 | - [ ] I have performed a self-review of my own code
24 | - [ ] I have commented my code, particularly in hard-to-understand areas
25 | - [ ] I have made corresponding changes to the documentation
26 | - [ ] My changes generate no new warnings
27 | - [ ] I have added tests that prove my fix is effective or that my feature works
28 | - [ ] New and existing unit tests pass locally with my changes
29 | - [ ] Any dependent changes have been merged and published in downstream modules
30 | - [ ] I have checked my code and corrected any misspellings
31 |
--------------------------------------------------------------------------------
/webpack.common.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | module.exports = {
4 | entry: {
5 | backgroundPage: path.join(__dirname, "src/backgroundPage.ts"),
6 | popup: path.join(__dirname, "src/popup/index.tsx"),
7 | },
8 | output: {
9 | path: path.join(__dirname, "dist/js"),
10 | filename: "[name].js",
11 | },
12 | module: {
13 | rules: [
14 | {
15 | exclude: /node_modules/,
16 | test: /\.tsx?$/,
17 | use: "ts-loader",
18 | },
19 | // Treat src/css/app.css as a global stylesheet
20 | {
21 | test: /\app.css$/,
22 | use: [
23 | "style-loader",
24 | "css-loader",
25 | "postcss-loader",
26 | ],
27 | },
28 | // Load .module.css files as CSS modules
29 | {
30 | test: /\.module.css$/,
31 | use: [
32 | "style-loader",
33 | {
34 | loader: "css-loader",
35 | options: {
36 | modules: true,
37 | },
38 | },
39 | "postcss-loader",
40 | ],
41 | },
42 | ],
43 | },
44 | // Setup @src path resolution for TypeScript files
45 | resolve: {
46 | extensions: [".ts", ".tsx", ".js"],
47 | alias: {
48 | "@src": path.resolve(__dirname, "src/"),
49 | },
50 | },
51 | };
52 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing Guide
2 |
3 | Welcome and thanks for stopping by! There are many ways to contribute, including submitting bug reports, improving documentation, submitting feature requests, reviewing new submissions, or contributing code that can be incorporated into the project.
4 |
5 | **Table of Contents:**
6 |
7 | 1. [Code of Conduct](#code-of-conduct)
8 | 2. [Questions](#questions)
9 | 3. [Feature Requests](#feature-requests)
10 | 4. [Reporting Bugs](#reporting-bugs)
11 | 5. [Contributing Code](#contributing-code)
12 |
13 | ## Code of Conduct
14 |
15 | By participating in this project, you agree to abide by our [Code of Conduct][0].
16 |
17 | ## Questions
18 |
19 | Please open a GitHub issue if you have any questions about the project.
20 |
21 | ## Feature Requests
22 |
23 | Please request new features by opening a GitHub issue.
24 |
25 | ## Reporting Bugs
26 |
27 | **If you find a security vulnerability, do NOT open an issue. Email aeksco@gmail.COM instead.**
28 |
29 | Please check open issues before opening a new ticket. Also, provide any references to FAQs or debugging guides that you might have.
30 |
31 | ## Contributing Code
32 |
33 | Unsure where to begin contributing to this project? You can start by looking through open `help-wanted` issues!
34 |
35 | Working on your first open source project or pull request? Here are some helpful tutorials:
36 |
37 | - [How to Contribute to an Open Source Project on GitHub][1]
38 | - [Make a Pull Request][2]
39 | - [First Timers Only][3]
40 |
41 | [0]: CODE_OF_CONDUCT.md
42 | [1]: https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github
43 | [2]: http://makeapullrequest.com/
44 | [3]: http://www.firsttimersonly.com
45 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | All participants of `react-typescript-web-extension-starter` are expected to abide by our Code of Conduct, both online and during in-person events that are hosted and/or associated with `react-typescript-web-extension-starter`.
4 |
5 | ## The Pledge
6 |
7 | In the interest of fostering an open and welcoming environment, we pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
8 |
9 | ## The Standards
10 |
11 | Examples of behaviour that contributes to creating a positive environment include:
12 |
13 | - Using welcoming and inclusive language
14 | - Being respectful of differing viewpoints and experiences
15 | - Gracefully accepting constructive criticism
16 |
17 | Examples of unacceptable behaviour by participants include:
18 |
19 | - Trolling, insulting/derogatory comments, public or private harassment
20 | - Publishing others' private information, such as a physical or electronic address, without explicit permission
21 | - Not being respectful to reasonable communication boundaries, such as 'leave me alone,' 'go away,' or 'I’m not discussing this with you.'
22 | - The usage of sexualised language or imagery and unwelcome sexual attention or advances
23 | - Demonstrating the graphics or any other content you know may be considered disturbing
24 | - Starting and/or participating in arguments related to politics
25 | - Other conduct which you know could reasonably be considered inappropriate in a professional setting.
26 |
27 | ## Enforcement
28 |
29 | Violations of the Code of Conduct may be reported by sending an email to `aeksco at gmail.com`. All reports will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Further details of specific enforcement policies may be posted separately.
30 |
31 | We hold the right and responsibility to remove comments or other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any members for other behaviours that they deem inappropriate, threatening, offensive, or harmful.
32 |
33 | ## Attribution
34 |
35 | This Code of Conduct is adapted from dev.to.
36 |
--------------------------------------------------------------------------------
/src/popup/component.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Hello } from "@src/components/hello";
3 | import browser, { Tabs } from "webextension-polyfill";
4 | import { Scroller } from "@src/components/scroller";
5 | import css from "./styles.module.css";
6 |
7 | // // // //
8 |
9 | // Scripts to execute in current tab
10 | const scrollToTopPosition = 0;
11 | const scrollToBottomPosition = 9999999;
12 |
13 | function scrollWindow(position: number) {
14 | window.scroll(0, position);
15 | }
16 |
17 | /**
18 | * Executes a string of Javascript on the current tab
19 | * @param code The string of code to execute on the current tab
20 | */
21 | function executeScript(position: number): void {
22 | // Query for the active tab in the current window
23 | browser.tabs
24 | .query({ active: true, currentWindow: true })
25 | .then((tabs: Tabs.Tab[]) => {
26 | // Pulls current tab from browser.tabs.query response
27 | const currentTab: Tabs.Tab | number = tabs[0];
28 |
29 | // Short circuits function execution is current tab isn't found
30 | if (!currentTab) {
31 | return;
32 | }
33 | const currentTabId: number = currentTab.id as number;
34 |
35 | // Executes the script in the current tab
36 | browser.scripting
37 | .executeScript({
38 | target: {
39 | tabId: currentTabId,
40 | },
41 | func: scrollWindow,
42 | args: [position],
43 | })
44 | .then(() => {
45 | console.log("Done Scrolling");
46 | });
47 | });
48 | }
49 |
50 | // // // //
51 |
52 | export function Popup() {
53 | // Sends the `popupMounted` event
54 | React.useEffect(() => {
55 | browser.runtime.sendMessage({ popupMounted: true });
56 | }, []);
57 |
58 | // Renders the component tree
59 | return (
60 |
74 | );
75 | }
76 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-typescript-chrome-extension-starter",
3 | "version": "2.0.0",
4 | "description": "Web Extension starter kit built with React, TypeScript, Tailwind CSS, EsLint, Prettier & Webpack",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "webpack --config webpack.prod.js",
8 | "dev": "webpack -w --config webpack.dev.js",
9 | "test": "jest --config=jest.config.js",
10 | "lint": "eslint --fix -c ./.eslintrc.js \"src/**/*.ts*\"",
11 | "prettify": "prettier --write \"src/**/*.ts*\"",
12 | "storybook": "start-storybook -p 6006",
13 | "build-storybook": "build-storybook"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/aeksco/react-typescript-chrome-extension-starter.git"
18 | },
19 | "keywords": [
20 | "react",
21 | "typescript",
22 | "chrome",
23 | "extension",
24 | "boilerplate"
25 | ],
26 | "author": "Alexander Schwartzberg",
27 | "license": "MIT",
28 | "bugs": {
29 | "url": "https://github.com/aeksco/react-typescript-chrome-extension-starter/issues"
30 | },
31 | "homepage": "https://github.com/aeksco/react-typescript-chrome-extension-starter#readme",
32 | "devDependencies": {
33 | "@babel/core": "^7.11.6",
34 | "@babel/preset-env": "^7.11.5",
35 | "@babel/preset-typescript": "^7.10.4",
36 | "@storybook/addon-essentials": "^6.4.9",
37 | "@storybook/addon-interactions": "^6.4.9",
38 | "@storybook/builder-webpack5": "^6.4.9",
39 | "@storybook/manager-webpack5": "^6.4.9",
40 | "@storybook/react": "^6.4.9",
41 | "@storybook/testing-library": "^0.0.7",
42 | "@types/chrome": "^0.0.124",
43 | "@types/jest": "^26.0.14",
44 | "@types/node": "^14.11.8",
45 | "@types/react": "^17.0.2",
46 | "@types/react-dom": "^17.0.2",
47 | "@types/react-test-renderer": "^17.0.1",
48 | "@types/webextension-polyfill": "^0.9.0",
49 | "@typescript-eslint/eslint-plugin": "^4.4.1",
50 | "@typescript-eslint/parser": "^4.4.1",
51 | "autoprefixer": "^10.4.1",
52 | "awesome-typescript-loader": "^5.2.1",
53 | "babel-core": "^6.26.3",
54 | "babel-jest": "^26.5.2",
55 | "babel-loader": "^8.1.0",
56 | "css-loader": "^4.3.0",
57 | "eslint": "^7.11.0",
58 | "eslint-config-prettier": "^6.12.0",
59 | "eslint-plugin-prettier": "^3.1.4",
60 | "eslint-plugin-react": "^7.21.4",
61 | "jest": "^26.5.3",
62 | "jest-css-modules": "^2.1.0",
63 | "postcss": "^8.4.31",
64 | "postcss-loader": "^6.2.1",
65 | "prettier": "^2.1.2",
66 | "react-test-renderer": "^17.0.2",
67 | "tailwindcss": "^3.0.8",
68 | "ts-jest": "^26.4.1",
69 | "ts-loader": "^8.0.5",
70 | "typescript": "^4.0.3",
71 | "webpack": "^5.76.0",
72 | "webpack-cli": "^4.9.1",
73 | "webpack-merge": "^5.8.0"
74 | },
75 | "dependencies": {
76 | "react": "^17.0.2",
77 | "react-dom": "^17.0.2",
78 | "webextension-polyfill": "^0.9.0"
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/.storybook/main.js:
--------------------------------------------------------------------------------
1 | const webpack = require("webpack");
2 | const path = require("path");
3 |
4 | module.exports = {
5 | stories: ["../src/**/*.stories.tsx"],
6 | addons: [
7 | "@storybook/addon-essentials",
8 | "@storybook/addon-interactions",
9 | ],
10 | // Enable the Storybook Interactions debugger
11 | // Docs: https://storybook.js.org/addons/@storybook/addon-interactions
12 | features: {
13 | interactionsDebugger: true,
14 | },
15 | // Configure Storybook to use Webpack@5.x
16 | // Docs: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#webpack-5
17 | core: {
18 | builder: "webpack5",
19 | },
20 | webpackFinal: async (config) => {
21 | // Setup @src path resolution for TypeScript files
22 | config.resolve = {
23 | ...config.resolve,
24 | extensions: [".ts", ".tsx", ".js"],
25 | alias: {
26 | "@src": path.resolve(__dirname, "../src/"),
27 | },
28 | };
29 |
30 | // Setup module replacement for mocked webextension-polyfill
31 | config.plugins = [
32 | ...config.plugins,
33 | new webpack.NormalModuleReplacementPlugin(
34 | /webextension-polyfill/,
35 | (resource) => {
36 | // Gets absolute path to mock `webextension-polyfill-ts` package
37 | // NOTE: this is required beacuse the `webextension-polyfill-ts`
38 | // package can't be used outside the environment provided by web extensions
39 | const absRootMockPath = path.resolve(
40 | __dirname,
41 | "../src/__mocks__/webextension-polyfill.ts",
42 | );
43 |
44 | // Gets relative path from requesting module to our mocked module
45 | const relativePath = path.relative(
46 | resource.context,
47 | absRootMockPath,
48 | );
49 |
50 | // Updates the `resource.request` to reference our mocked module instead of the real one
51 | switch (process.platform) {
52 | case "win32": {
53 | resource.request = "./" + relativePath;
54 | break;
55 | }
56 | default: {
57 | resource.request = relativePath;
58 | break;
59 | }
60 | }
61 | },
62 | ),
63 | ];
64 |
65 | // Remove the default .css webpack module rule
66 | // This is necessary because we use both global CSS and CSS modules
67 | // in the extension and in Storybook
68 | config.module.rules = config.module.rules.filter((r) => {
69 | if (".css".match(r.test)) {
70 | return false;
71 | }
72 | return true
73 | })
74 |
75 | // Treat src/css/app.css as a global stylesheet
76 | config.module.rules.push({
77 | test: /\app.css$/,
78 | use: [
79 | "style-loader",
80 | "css-loader",
81 | "postcss-loader",
82 | ],
83 | })
84 |
85 | // Load .module.css files as CSS modules
86 | config.module.rules.push({
87 | test: /\.module.css$/,
88 | use: [
89 | "style-loader",
90 | {
91 | loader: "css-loader",
92 | options: {
93 | modules: true,
94 | },
95 | },
96 | "postcss-loader",
97 | ],
98 | })
99 |
100 | // Return the final Webpack configuration
101 | return config;
102 | },
103 | };
104 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | // For a detailed explanation regarding each configuration property, visit:
2 | // https://jestjs.io/docs/en/configuration.html
3 |
4 | module.exports = {
5 | // All imported modules in your tests should be mocked automatically
6 | // automock: false,
7 | // Stop running tests after `n` failures
8 | // bail: 0,
9 | // Respect "browser" field in package.json when resolving modules
10 | // browser: false,
11 | // The directory where Jest should store its cached dependency information
12 | // cacheDirectory: "/tmp/jest_rs",
13 | // Automatically clear mock calls and instances between every test
14 | // clearMocks: true,
15 | // Indicates whether the coverage information should be collected while executing the test
16 | // collectCoverage: false,
17 | // An array of glob patterns indicating a set of files for which coverage information should be collected
18 | // collectCoverageFrom: null,
19 | // The directory where Jest should output its coverage files
20 | // coverageDirectory: "coverage",
21 | // An array of regexp pattern strings used to skip coverage collection
22 | // coveragePathIgnorePatterns: [
23 | // "/node_modules/"
24 | // ],
25 | // A list of reporter names that Jest uses when writing coverage reports
26 | // coverageReporters: [
27 | // "json",
28 | // "text",
29 | // "lcov",
30 | // "clover"
31 | // ],
32 | // An object that configures minimum threshold enforcement for coverage results
33 | // coverageThreshold: null,
34 | // A path to a custom dependency extractor
35 | // dependencyExtractor: null,
36 | // Make calling deprecated APIs throw helpful error messages
37 | // errorOnDeprecated: false,
38 | // Force coverage collection from ignored files using an array of glob patterns
39 | // forceCoverageMatch: [],
40 | // A path to a module which exports an async function that is triggered once before all test suites
41 | // globalSetup: null,
42 | // A path to a module which exports an async function that is triggered once after all test suites
43 | // globalTeardown: null,
44 | // A set of global variables that need to be available in all test environments
45 | // globals: {},
46 | // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
47 | // maxWorkers: "50%",
48 | // An array of directory names to be searched recursively up from the requiring module's location
49 | // moduleDirectories: [
50 | // "node_modules"
51 | // ],
52 | // An array of file extensions your modules use
53 | moduleFileExtensions: ["js", "json", "jsx", "ts", "tsx", "node"],
54 | // A map from regular expressions to module names that allow to stub out resources with a single module
55 | moduleNameMapper: {
56 | "@src/(.*)": "/src/$1",
57 | "\\.(css|less|scss|sss|styl)$":
58 | "/node_modules/jest-css-modules",
59 | },
60 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
61 | // modulePathIgnorePatterns: [],
62 | // Activates notifications for test results
63 | // notify: false,
64 | // An enum that specifies notification mode. Requires { notify: true }
65 | // notifyMode: "failure-change",
66 | // A preset that is used as a base for Jest's configuration
67 | // preset: null,
68 | // Run tests from one or more projects
69 | // projects: null,
70 | // Use this configuration option to add custom reporters to Jest
71 | // reporters: undefined,
72 | // Automatically reset mock state between every test
73 | // resetMocks: false,
74 | // Reset the module registry before running each individual test
75 | // resetModules: false,
76 | // A path to a custom resolver
77 | // resolver: null,
78 | // Automatically restore mock state between every test
79 | // restoreMocks: false,
80 | // The root directory that Jest should scan for tests and modules within
81 | // rootDir: null,
82 | // A list of paths to directories that Jest should use to search for files in
83 | roots: ["/src"],
84 | // Allows you to use a custom runner instead of Jest's default test runner
85 | // runner: "jest-runner",
86 | // The paths to modules that run some code to configure or set up the testing environment before each test
87 | // setupFiles: [],
88 | // A list of paths to modules that run some code to configure or set up the testing framework before each test
89 | // setupFilesAfterEnv: [],
90 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing
91 | // snapshotSerializers: [],
92 | // The test environment that will be used for testing
93 | // testEnvironment: "jest-environment-jsdom",
94 | // Options that will be passed to the testEnvironment
95 | // testEnvironmentOptions: {},
96 | // Adds a location field to test results
97 | // testLocationInResults: false,
98 | // The glob patterns Jest uses to detect test files
99 | // testMatch: [
100 | // "**/__tests__/**/*.[jt]s?(x)",
101 | // "**/?(*.)+(spec|test).[tj]s?(x)"
102 | // ],
103 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
104 | testPathIgnorePatterns: ["/node_modules/", "stories.tsx"],
105 | // The regexp pattern or array of patterns that Jest uses to detect test files
106 | // testRegex: [],
107 | // This option allows the use of a custom results processor
108 | // testResultsProcessor: null,
109 | // This option allows use of a custom test runner
110 | // testRunner: "jasmine2",
111 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
112 | // testURL: "http://localhost",
113 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
114 | // timers: "real",
115 | // A map from regular expressions to paths to transformers
116 | // transform: null,
117 | transform: {
118 | "\\.tsx?$": "ts-jest",
119 | },
120 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
121 | // transformIgnorePatterns: ["/node_modules/"],
122 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
123 | // unmockedModulePathPatterns: undefined,
124 | // Indicates whether each individual test should be reported during the run
125 | // verbose: null,
126 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
127 | // watchPathIgnorePatterns: [],
128 | // Whether to use watchman for file crawling
129 | // watchman: true,
130 | };
131 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | []()
2 | []()
3 | []()
4 | [](https://github.com/aeksco/react-typescript-web-extension-starter/graphs/contributors)
5 | [](https://github.com/aeksco/react-typescript-web-extension-starter/blob/main/LICENSE)
6 | [](https://github.com/aeksco/react-typescript-web-extension-starter/issues)
7 | [](https://github.com/aeksco/react-typescript-web-extension-starter/commits/master)
8 | []()
9 | [](http://makeapullrequest.com)
10 |
11 | [](http://hits.dwyl.com/aeksco/react-typescript-web-extension-starter)
12 | [](https://twitter.com/intent/tweet?text=https://github.com/aeksco/react-typescript-web-extension-starter)
13 | [](https://twitter.com/aeksco)
14 |
15 | 
16 |
17 | :desktop_computer: A Web Extension starter kit built with React, TypeScript, Storybook, EsLint, Prettier, Jest, TailwindCSS, & Webpack. Compatible with Google Chrome, Mozilla Firefox, Brave, and Microsoft Edge.
18 |
19 | 
20 |
21 | **Getting Started**
22 |
23 | Run the following commands to install dependencies and start developing
24 |
25 | ```
26 | yarn install
27 | yarn dev
28 | ```
29 |
30 | **Scripts**
31 |
32 | - `yarn dev` - run `webpack` in `watch` mode
33 | - `yarn storybook` - runs the Storybook server
34 | - `yarn build` - builds the production-ready unpacked extension
35 | - `yarn test -u` - runs Jest + updates test snapshots
36 | - `yarn lint` - runs EsLint
37 | - `yarn prettify` - runs Prettier
38 |
39 |
40 | Loading the extension in Google Chrome
41 |
42 | In [Google Chrome](https://www.google.com/chrome/), open up [chrome://extensions](chrome://extensions) in a new tab. Make sure the `Developer Mode` checkbox in the upper-right corner is turned on. Click `Load unpacked` and select the `dist` directory in this repository - your extension should now be loaded.
43 |
44 | 
45 |
46 |
47 |
48 |
49 | Loading the extension in Brave
50 |
51 | In [Brave](https://brave.com/), open up [brave://extensions](brave://extensions) in a new tab. Make sure the `Developer Mode` checkbox in the upper-right corner is turned on. Click `Load unpacked` and select the `dist` directory in this repository - your extension should now be loaded.
52 |
53 | 
54 |
55 |
56 |
57 |
58 | Loading the extension in Mozilla Firefox
59 |
60 | In [Mozilla Firefox](https://www.mozilla.org/en-US/firefox/new/), open up the [about:debugging](about:debugging) page in a new tab. Click the `This Firefox` link in the sidebar. One the `This Firefox` page, click the `Load Temporary Add-on...` button and select the `manifest.json` from the `dist` directory in this repository - your extension should now be loaded.
61 |
62 | 
63 |
64 |
65 |
66 |
67 | Loading the extension in Microsoft Edge
68 |
69 | In [Microsoft Edge](https://www.microsoft.com/en-us/edge), open up [edge://extensions](edge://extensions) in a new tab. Make sure the `Developer Mode` checkbox in the lower-left corner is turned on. Click `Load unpacked` and select the `dist` directory in this repository - your extension should now be loaded.
70 |
71 | 
72 |
73 |
74 |
75 | **Notes**
76 |
77 | - This project is a [repository template](https://github.blog/2019-06-06-generate-new-repositories-with-repository-templates/) - click the `Use this template` button to use this starter codebase for your next project.
78 |
79 | - Includes ESLint configured to work with TypeScript and Prettier.
80 |
81 | - Includes tests with Jest - note that the `babel.config.js` and associated dependencies are only necessary for Jest to work with TypeScript.
82 |
83 | - Recommended to use `Visual Studio Code` with the `Format on Save` setting turned on.
84 |
85 | - Example icons courtesy of [Heroicons](https://heroicons.com/).
86 |
87 | - Includes Storybook configured to work with React + TypeScript. Note that it maintains its own `webpack.config.js` and `tsconfig.json` files. See example story in `src/components/hello/__tests__/hello.stories.tsx`
88 |
89 | - Includes a custom mock for the [webextension-polyfill-ts](https://github.com/Lusito/webextension-polyfill-ts) package in `src/__mocks__`. This allows you to mock any browser APIs used by your extension so you can develop your components inside Storybook.
90 |
91 | **Built with**
92 |
93 | - [React](https://reactjs.org)
94 | - [TypeScript](https://www.typescriptlang.org/)
95 | - [Storybook](https://storybook.js.org/)
96 | - [Jest](https://jestjs.io)
97 | - [Eslint](https://eslint.org/)
98 | - [Prettier](https://prettier.io/)
99 | - [Webpack](https://webpack.js.org/)
100 | - [Babel](https://babeljs.io/)
101 | - [TailwindCSS](https://tailwindcss.com/)
102 | - [webextension-polyfill](https://github.com/mozilla/webextension-polyfill)
103 |
104 | **Misc. References**
105 |
106 | - [Chrome Extension Developer Guide](https://developer.chrome.com/extensions/devguide)
107 | - [Firefox Extension Developer Guide](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Your_first_WebExtension)
108 | - [Eslint + Prettier + Typescript Guide](https://dev.to/robertcoopercode/using-eslint-and-prettier-in-a-typescript-project-53jb)
109 |
110 | **Notable forks**
111 |
112 | - [capaj](https://github.com/capaj/react-typescript-web-extension-starter) - Chakra-ui instead of TailwindCSS, Storybook removed
113 | - [DesignString](https://github.com/DesignString/react-typescript-web-extension-starter) - Vite Js instead of Webpack
114 |
--------------------------------------------------------------------------------