├── .eslintignore ├── .eslintrc.cjs ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug.yml │ ├── config.yml │ ├── feature.yml │ └── question.yml ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── build.yml │ ├── close-stale.yml │ ├── issues.yml │ ├── lock.yml │ ├── nodejs.yml │ ├── prepare-cache.yml │ ├── test.yml │ └── webpack.yml ├── .gitignore ├── CHANGELOG_PRE_V4.md ├── CHANGELOG_V4+.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── jest.config.ci.mjs ├── jest.config.mjs ├── package.json ├── public ├── index.html └── style.css ├── src ├── main │ └── main.ts ├── preload │ ├── ipc-api.ts │ └── preload.ts ├── renderer │ ├── App.tsx │ └── renderer.tsx ├── types │ └── global.d.ts └── utils │ └── node-env.ts ├── tests ├── main │ └── main.spec.ts ├── tsconfig.json └── utils │ └── node-env.spec.ts ├── tsconfig.eslint.json ├── tsconfig.json └── webpack.config.mjs /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | coverage 4 | out 5 | public 6 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | const baseConfig = { 2 | env: { node: true }, 3 | plugins: ['import'], 4 | parser: '@typescript-eslint/parser', 5 | parserOptions: { 6 | project: ['./tsconfig.eslint.json'], 7 | }, 8 | extends: [ 9 | 'airbnb', 10 | 'airbnb/hooks', 11 | 'plugin:import/recommended', 12 | ], 13 | rules: { 14 | 'max-len': [ 15 | 'warn', 16 | { 17 | code: 80, 18 | tabWidth: 2, 19 | ignoreComments: true, 20 | }, 21 | ], 22 | 'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], 23 | 'import/order': [ 24 | 'error', 25 | { alphabetize: { order: 'asc' } }, 26 | ], 27 | }, 28 | }; 29 | 30 | const tsConfig = { 31 | files: ['*.ts', '*.tsx'], 32 | excludedFiles: ['*.spec.ts', '*.spec.tsx', '*.test.ts', '*.test.tsx'], 33 | plugins: [ 34 | ...baseConfig.plugins, 35 | '@typescript-eslint', 36 | ], 37 | extends: [ 38 | ...baseConfig.extends, 39 | 'airbnb-typescript', 40 | 'plugin:import/typescript', 41 | 'plugin:@typescript-eslint/recommended', 42 | 'plugin:@typescript-eslint/recommended-requiring-type-checking', 43 | ], 44 | rules: { 45 | ...baseConfig.rules, 46 | // disable rules covered by TypesScript compiler 47 | 'import/default': 'off', 48 | 'import/named': 'off', 49 | 'import/namespace': 'off', 50 | 'import/no-named-as-default-member': 'off', 51 | // disable rules for better local performance 52 | 'import/no-cycle': 'off', 53 | 'import/no-deprecated': 'off', 54 | 'import/no-named-as-default': 'off', 55 | 'import/no-unused-modules': 'off', 56 | }, 57 | settings: { 58 | 'import/parsers': { '@typescript-eslint/parser': ['.ts', '.tsx'] }, 59 | 'import/resolver': { 60 | typescript: { 61 | alwaysTryTypes: true, 62 | project: ['./tsconfig.eslint.json'], 63 | }, 64 | }, 65 | }, 66 | }; 67 | 68 | const jestConfig = { 69 | files: ['*.spec.ts', '*.spec.tsx', '*.test.ts', '*.test.tsx'], 70 | env: { node: true, 'jest/globals': true }, 71 | plugins: [ 72 | ...tsConfig.plugins, 73 | 'jest', 74 | ], 75 | extends: [ 76 | ...tsConfig.extends, 77 | 'plugin:jest/recommended', 78 | 'plugin:jest/style', 79 | ], 80 | rules: { 81 | ...tsConfig.rules, 82 | 'import/no-extraneous-dependencies': 'off', 83 | '@typescript-eslint/no-non-null-assertion': 'off', 84 | }, 85 | settings: tsConfig.settings, 86 | }; 87 | 88 | const specialConfig = { 89 | files: [ 90 | '**/*.config.js', 91 | '**/*.config.cjs', 92 | '**/*.config.mjs', 93 | '**/*.config.*.js', 94 | '**/*.config.*.cjs', 95 | '**/*.config.*.mjs', 96 | ], 97 | rules: { 98 | ...baseConfig.rules, 99 | 'import/no-extraneous-dependencies': 'off', 100 | }, 101 | }; 102 | 103 | module.exports = { 104 | root: true, 105 | ...baseConfig, 106 | overrides: [ 107 | tsConfig, 108 | jestConfig, 109 | specialConfig, 110 | ], 111 | }; 112 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [iamWing] 4 | patreon: # Replace with a single Patreon username 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 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://paypal.me/iamWing0w0'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## 👉 [Please follow one of these issue templates](https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/issues/new/choose) 👈 2 | 3 | Note: to keep the backlog clean and actionable, issues may be immediately closed if they do not follow one of the above issue templates. 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 🪲 2 | description: Create a bug report to help us improve 3 | title: '[Bug]: ' 4 | labels: ['Bug Report'] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | # Please follow these steps first: 10 | - type: markdown 11 | attributes: 12 | value: | 13 | ## Troubleshoot 14 | If the boilerplate is not behaving the way you expect, we'd ask you to look at the [README](https://github.com/Devtography/electron-react-typescript-webpack-boilerplate#readme) and search the issue tracker before submitting the issue. Please make reasonable efforts to troubleshoot and rule out issues with your code, the configuration, or any 3rd party libraries you might be using. 15 | - type: markdown 16 | attributes: 17 | value: | 18 | ## Ask for help through appropriate channels 19 | If you feel unsure about the cause of the problem, consider asking for help on for example [StackOverflow](https://stackoverflow.com/questions/ask) or our [Discussions section](https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/discussions) before posting a bug report. This issue tracker is not a help forum. 20 | - type: markdown 21 | attributes: 22 | value: | 23 | ## Make a minimal reproduction 24 | To file the report, you will need a GitHub repository with a minimal (but complete) example and simple/clear steps on how to reproduce the bug. If all your tests fail with a strange error, can you find a way to show us with just one? If you have many extra configuration options in your config files, can you simplify them? 25 | 26 | The simpler you can make it, the more likely we are to successfully verify and fix the bug. 27 | - type: markdown 28 | attributes: 29 | value: | 30 | :bangbang: Bug reports without a minimal reproduction will be rejected. :bangbang: 31 | 32 | --- 33 | 34 | - type: input 35 | id: version 36 | attributes: 37 | label: Version 38 | description: | 39 | The version of ERTW boilerplate you are using. 40 | Is it the [latest](https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/releases)? Test and see if the bug has already been fixed. 41 | placeholder: ex. 4.1.2 42 | validations: 43 | required: true 44 | - type: textarea 45 | id: reproduction 46 | attributes: 47 | label: Steps to reproduce 48 | description: Please link to a repository with a minimal reproduction and describe accurately how we can reproduce/verify the bug. 49 | placeholder: | 50 | Example steps (replace with your own): 51 | 1. Clone my repo at https://github.com//example 52 | 2. npm ci 53 | 3. npm test 54 | 4. You should see the error comes up 55 | validations: 56 | required: true 57 | - type: textarea 58 | id: expected 59 | attributes: 60 | label: Expected behaviour 61 | description: A description of what you expect to happen. 62 | placeholder: I expect to see X or Y 63 | validations: 64 | required: true 65 | - type: textarea 66 | id: what-happened 67 | attributes: 68 | label: Actual behaviour 69 | description: A clear and concise description of the unexpected behaviour. 70 | placeholder: A bug happened! 71 | validations: 72 | required: true 73 | - type: textarea 74 | id: context 75 | attributes: 76 | label: Additional context 77 | description: Anything else that might be relevant. 78 | validations: 79 | required: true 80 | - type: textarea 81 | id: envinfo 82 | attributes: 83 | label: Environment 84 | description: | 85 | Please paste the output of running `npx envinfo --system --binaries --npmPackages` 86 | placeholder: | 87 | System: 88 | OS: Linux 5.4 Ubuntu 20.04.4 LTS (Focal Fossa) 89 | CPU: (4) x64 Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz 90 | Memory: 5.10 GB / 7.77 GB 91 | Container: Yes 92 | Shell: 5.0.17 - /bin/bash 93 | Binaries: 94 | Node: 16.17.0 - ~/.nvm/versions/node/v16.17.0/bin/node 95 | Yarn: 1.22.15 - /opt/yarn/stable/bin/yarn 96 | npm: 8.19.1 - ~/.nvm/versions/node/v16.17.0/bin/npm 97 | npmPackages: 98 | @types/jest: ^28.1.6 => 28.1.6 99 | @types/react: ^18.0.17 => 18.0.17 100 | @types/react-dom: ^18.0.6 => 18.0.6 101 | @typescript-eslint/eslint-plugin: ^5.33.0 => 5.33.0 102 | @typescript-eslint/parser: ^5.33.0 => 5.33.0 103 | cross-env: ^7.0.3 => 7.0.3 104 | electron: ^20.0.2 => 20.0.2 105 | eslint: ^8.22.0 => 8.22.0 106 | eslint-config-airbnb: ^19.0.4 => 19.0.4 107 | eslint-config-airbnb-typescript: ^17.0.0 => 17.0.0 108 | eslint-import-resolver-typescript: ^3.4.1 => 3.4.1 109 | eslint-plugin-import: ^2.26.0 => 2.26.0 110 | eslint-plugin-jest: ^26.8.2 => 26.8.2 111 | eslint-plugin-jsx-a11y: ^6.6.1 => 6.6.1 112 | eslint-plugin-react: ^7.30.1 => 7.30.1 113 | eslint-plugin-react-hooks: ^4.6.0 => 4.6.0 114 | jest: ^28.1.3 => 28.1.3 115 | react: ^18.2.0 => 18.2.0 116 | react-dom: ^18.2.0 => 18.2.0 117 | ts-jest: ^28.0.7 => 28.0.7 118 | typescript: ^4.7.4 => 4.7.4 119 | render: Shell 120 | validations: 121 | required: true 122 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.yml: -------------------------------------------------------------------------------- 1 | name: Feature Proposal 🚀 2 | description: Submit a proposal for a new feature 3 | title: '[Feature]: ' 4 | labels: [':rocket: Feature Request'] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | ### Thank you for taking the time to suggest a new feature! 10 | - type: textarea 11 | id: description 12 | attributes: 13 | label: '🚀 Feature Proposal' 14 | description: A clear and concise description of what the feature is. 15 | validations: 16 | required: true 17 | - type: textarea 18 | id: solution 19 | attributes: 20 | label: Motivation 21 | description: Outline your motivation for the proposal. How will it make the boilerplate better? 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: example 26 | attributes: 27 | label: Example 28 | description: Describe how this feature would be used. 29 | validations: 30 | required: false 31 | - type: textarea 32 | id: extra 33 | attributes: 34 | label: Pitch 35 | description: Why does this feature belong in the boilerplate? 36 | validations: 37 | required: true 38 | - type: markdown 39 | attributes: 40 | value: | 41 | Common proposals that do not typically make it into the boilerplate: 42 | 43 | - Experimental features 44 | - Uncommon features/settings for Electron apps development 45 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.yml: -------------------------------------------------------------------------------- 1 | name: 'Questions / Help 💬' 2 | description: If you have question, please check StackOverflow first for the relevant package(s) in concern 3 | title: '[Please read the message below]' 4 | labels: [':speech_balloon: Question'] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | ## Questions and Help 💬 10 | 11 | This issue tracker is reserved for bug reports and feature proposals. 12 | 13 | For anything else, such as questions or getting help, please see: 14 | 15 | - [Discussions](https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/discussions) 16 | - [StackOverflow](https://stackoverflow.com) for whichever package(s) in concern 17 | 18 | If you're having questions about the boilerplate or want to ask for help, start a thread in [Discussions](https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/discussions) instead. 19 | - type: checkboxes 20 | id: no-post 21 | attributes: 22 | label: Please do not submit this issue. 23 | description: | 24 | :bangbang: This issue will be closed. :bangbang: 25 | options: 26 | - label: I understand 27 | required: true 28 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ## Summary 6 | 7 | 8 | 9 | ## Test plan 10 | 11 | 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: daily 7 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build app package 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | os: 7 | required: true 8 | type: string 9 | test-only: 10 | required: false 11 | type: boolean 12 | 13 | jobs: 14 | setup-matrix: 15 | runs-on: ${{ inputs.os }} 16 | outputs: 17 | node_versions: ${{ steps.generate-matrix.outputs.node_versions }} 18 | steps: 19 | - name: Generate matrix 20 | id: generate-matrix 21 | run: | 22 | if [ "${{ inputs.test-only }}" = "true" ]; then 23 | VERSIONS='["14.x", "16.x"]' 24 | else 25 | VERSIONS='["16.x"]' 26 | fi 27 | echo ::set-output name=node_versions::"$VERSIONS" 28 | shell: bash 29 | 30 | build-app-package: 31 | needs: setup-matrix 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | node-version: ${{ fromJSON(needs.setup-matrix.outputs.node_versions) }} 36 | name: Build app package with Node v${{ matrix.node-version }} on ${{ inputs.os }} 37 | runs-on: ${{ inputs.os }} 38 | 39 | steps: 40 | - uses: actions/checkout@v3 41 | 42 | - name: Use Node.js ${{ matrix.node-version }} 43 | uses: actions/setup-node@v3 44 | with: 45 | node-version: ${{ matrix.node-version }} 46 | cache: npm 47 | 48 | - name: Prepare Webpack bundle cache 49 | id: cache-webpack-bundles 50 | uses: actions/cache@v3 51 | with: 52 | path: ./dist 53 | key: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}-webpack-${{ inputs.os }} 54 | 55 | - name: Install 56 | run: npm ci 57 | 58 | - if: ${{ steps.cache-webpack-bundles.outputs.cache-hit != 'true' }} 59 | name: Run webpack 60 | run: npm run prod 61 | 62 | - if: ${{ inputs.os == 'ubuntu-latest' }} 63 | name: Build app package on ${{ inputs.os }} 64 | run: | 65 | echo "Build on Linux is not yet supported." 66 | exit 1 67 | 68 | - if: ${{ inputs.os == 'macos-latest' }} 69 | name: Build Windows & mac app packages on ${{ inputs.os }} 70 | run: | 71 | if [ "${{ inputs.test-only }}" = "true" ]; then 72 | npm run build:mac -- --publish never 73 | npm run build:win -- --publish never 74 | else 75 | npm run build:mac 76 | npm run build:win 77 | fi 78 | 79 | - if: ${{ inputs.os == 'windows-latest' }} 80 | name: Build Windows app package on ${{ inputs.os }} 81 | run: | 82 | if [ "${{ inputs.test-only }}" = "true" ]; then 83 | npm run build:win -- --publish never 84 | else 85 | npm run build:win 86 | fi 87 | shell: bash 88 | -------------------------------------------------------------------------------- /.github/workflows/close-stale.yml: -------------------------------------------------------------------------------- 1 | name: Close stale issues and PRs 2 | 3 | on: 4 | schedule: 5 | - cron: '0 23 * * *' 6 | 7 | permissions: 8 | issues: write 9 | pull-requests: write 10 | 11 | jobs: 12 | stale: 13 | name: Close month old issues and PRs 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/stale@v6 17 | with: 18 | stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days.' 19 | stale-pr-message: 'This PR is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 30 days.' 20 | close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity. Please open a new issue if the issus is still relevant, linking to this one.' 21 | close-pr-message: 'This PR was closed because it has been stalled for 14 days with no activity. Please open a new PR if the issue is still relevant, linking to this one.' 22 | days-before-issue-stale: 30 23 | days-before-pr-stale: 90 24 | days-before-issue-close: 7 25 | days-before-pr-close: 14 26 | exempt-all-milestones: true 27 | exempt-issue-labels: Pinned 28 | exempt-draft-pr: true 29 | -------------------------------------------------------------------------------- /.github/workflows/issues.yml: -------------------------------------------------------------------------------- 1 | name: 'Close issues' 2 | 3 | on: 4 | issues: 5 | types: [labeled] 6 | 7 | jobs: 8 | questions: 9 | name: Questions 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Close issue 13 | uses: peter-evans/close-issue@v2 14 | if: "${{ github.event.label.name == ':speech_ballon: Question' }}" 15 | with: 16 | comment: Please note this issue tracker is not a help forum. We recommend using [Discussions](https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/discussions) for questions. 17 | bug-without-repro: 18 | name: Bug reports without reproductions 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Close issue 22 | uses: peter-evans/close-issue@v2 23 | if: "${{ github.event.label.name == 'Needs Reproduction' }}" 24 | with: 25 | comment: As noted in the [Bug Report template](https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/blob/develop/.github/ISSUE_TEMPLATE/bug.yml), all bug reports require a minimal reproduction. Please open a new issue providing one. Read more at https://stackoverflow.com/help/minimal-reproducible-example. 26 | -------------------------------------------------------------------------------- /.github/workflows/lock.yml: -------------------------------------------------------------------------------- 1 | name: Lock Threads 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | workflow_dispatch: 7 | 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | concurrency: 13 | group: lock 14 | 15 | jobs: 16 | lock: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: dessant/lock-threads@v3 20 | with: 21 | github-token: ${{ github.token }} 22 | issue-inactive-days: '30' 23 | exclude-any-issue-labels: 'Discussion' 24 | issue-comment: > 25 | This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. 26 | 27 | Please note this issue tracker is not a help forum. We recommend using [Discussions](https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/discussions) for questions. 28 | 29 | pr-inactive-days: '30' 30 | pr-comment: > 31 | This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new pull request for related bugs. 32 | 33 | Please note this issue tracker is not a help forum. We recommend using [Discussions](https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/discussions) for questions. 34 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | - develop 9 | - 'release/**' 10 | pull_request: 11 | branches: 12 | - '**' 13 | 14 | concurrency: 15 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | prepare-npm-cache-ubuntu: 20 | uses: ./.github/workflows/prepare-cache.yml 21 | with: 22 | os: ubuntu-latest 23 | prepare-npm-cache-macos: 24 | uses: ./.github/workflows/prepare-cache.yml 25 | with: 26 | os: macos-latest 27 | prepare-npm-cache-windows: 28 | uses: ./.github/workflows/prepare-cache.yml 29 | with: 30 | os: windows-latest 31 | 32 | lint: 33 | name: Lint 34 | runs-on: ubuntu-latest 35 | needs: prepare-npm-cache-ubuntu 36 | 37 | steps: 38 | - uses: actions/checkout@v3 39 | - uses: actions/setup-node@v3 40 | with: 41 | node-version: lts/* 42 | cache: npm 43 | - name: install 44 | run: npm ci 45 | - name: run eslint 46 | run: npm run lint 47 | 48 | test-ubuntu: 49 | uses: ./.github/workflows/test.yml 50 | needs: prepare-npm-cache-ubuntu 51 | with: 52 | os: ubuntu-latest 53 | test-macos: 54 | uses: ./.github/workflows/test.yml 55 | needs: prepare-npm-cache-macos 56 | with: 57 | os: macos-latest 58 | test-windows: 59 | uses: ./.github/workflows/test.yml 60 | needs: prepare-npm-cache-windows 61 | with: 62 | os: windows-latest 63 | 64 | bundle-linux: 65 | uses: ./.github/workflows/webpack.yml 66 | needs: test-ubuntu 67 | with: 68 | os: ubuntu-latest 69 | bundle-mac: 70 | uses: ./.github/workflows/webpack.yml 71 | needs: test-macos 72 | with: 73 | os: macos-latest 74 | bundle-windows: 75 | uses: ./.github/workflows/webpack.yml 76 | needs: test-windows 77 | with: 78 | os: windows-latest 79 | 80 | build-mac: 81 | uses: ./.github/workflows/build.yml 82 | needs: bundle-mac 83 | with: 84 | os: macos-latest 85 | test-only: true 86 | build-windows: 87 | uses: ./.github/workflows/build.yml 88 | needs: bundle-windows 89 | with: 90 | os: windows-latest 91 | test-only: true 92 | -------------------------------------------------------------------------------- /.github/workflows/prepare-cache.yml: -------------------------------------------------------------------------------- 1 | name: Prepare CI cache 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | os: 7 | required: true 8 | type: string 9 | 10 | jobs: 11 | prepare-npm-cache: 12 | name: Prepare npm cache for ${{ inputs.os }} 13 | runs-on: ${{ inputs.os }} 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | 18 | - uses: actions/setup-node@v3 19 | with: 20 | node-version: lts/* 21 | cache: npm 22 | 23 | - name: Validate cache 24 | run: npm ci --omit optional 25 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | os: 7 | required: true 8 | type: string 9 | 10 | jobs: 11 | test: 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | node-version: [14.x, 16.x] 16 | name: Node v${{ matrix.node-version }} on ${{ inputs.os }} 17 | runs-on: ${{ inputs.os }} 18 | 19 | steps: 20 | - uses: actions/checkout@v3 21 | - name: Use Node.js ${{ matrix.node-version }} 22 | uses: actions/setup-node@v3 23 | with: 24 | node-version: ${{ matrix.node-version }} 25 | cache: npm 26 | - name: Install 27 | run: npm ci --omit optional 28 | - name: Run tests 29 | run: npm run jest-ci 30 | -------------------------------------------------------------------------------- /.github/workflows/webpack.yml: -------------------------------------------------------------------------------- 1 | name: Webpack CI 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | os: 7 | required: true 8 | type: string 9 | 10 | jobs: 11 | build-bundle: 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | node-version: [14.x, 16.x] 16 | name: Build Webpack bundles with Node v${{ matrix.node-version }} on ${{ inputs.os }} 17 | runs-on: ${{ inputs.os }} 18 | 19 | steps: 20 | - uses: actions/checkout@v3 21 | 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v3 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | cache: npm 27 | 28 | - name: Cache Webpack bundles 29 | id: cache-webpack-bundles 30 | uses: actions/cache@v3 31 | with: 32 | path: ./dist 33 | key: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}-webpack-${{ inputs.os }} 34 | 35 | - name: Install 36 | run: npm ci 37 | - name: Run webpack 38 | run: npm run prod 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | coverage/ 3 | dist/ 4 | node_modules/ 5 | out/ 6 | 7 | # Logs 8 | logs 9 | *.log 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Yarn Integrity file 15 | .yarn-integrity 16 | 17 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # Optional npm cache directory 21 | .npm 22 | 23 | # Optional eslint cache 24 | .eslintcache 25 | 26 | # Windows thumbnail cache files 27 | Thumbs.db 28 | 29 | # OS X files 30 | .DS_Store 31 | ._* -------------------------------------------------------------------------------- /CHANGELOG_PRE_V4.md: -------------------------------------------------------------------------------- 1 | # Changelog (pre `v4`) 2 | All notable changes up to `v3.0.0` are documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 5 | 6 | ## [3.0.0] - 2020-12-26 7 | ### Added 8 | - NPM packages `react-router` & `react-router-dom` to package dependencies. 9 | - NPM package `eslint-plugin-react-hooks` to `devDependencies` as required by the updated version of `eslint-config-airbnb`. 10 | - NPM package `copy-webpack-plugin` to `devDependencies` as replacement of `copy-pkg-json-webpack-plugin`. 11 | - NPM packages `@typescript-eslint/eslint-plugin` & `@typescript-eslint/parser` to `devDependencies` for using ESLint to lint TypeScript. 12 | 13 | ### Changed 14 | - __Project is now being developed based on Node.js `v14 (LTS)`.__ 15 | - Minor version upgrades on package dependencies: 16 | - `eslint-import-resolver-webpack` - `0.11.1` -> `0.13.0` 17 | - `eslint-plugin-import` - `2.18.2` -> `2.22.1` 18 | - `eslint-plugin-jsx-a11y` - `6.2.3` -> `6.4.1` 19 | - `eslint-plugin-react` - `7.17.0` -> ``7.21.5` 20 | - `lodash` - `4.17.15` -> `4.17.20` 21 | - Major version upgrades on package dependencies: 22 | - `react` & `react-dom` - `16.12.0` -> `17.0.1` 23 | - `cross-env` - `5.2.1` -> `7.0.3` 24 | - `css-loader` - `1.0.1` -> `5.0.1` 25 | - `electron` - `3.1.13` -> `11.1.1` 26 | - `electron-builder` - `20.44.4` -> `22.9.1` 27 | - `eslint` - `5.16.0` -> `7.16.0` 28 | - `eslint-config-airbnb` - `17.1.1` -> `18.2.1` 29 | - `file-loader` - `2.0.0` -> `6.2.0` 30 | - `html-webpack-plugin` - `3.2.0` -> `4.5.0` 31 | - `mocha` - `5.2.0` -> `8.2.1` 32 | - `rimraf` - `2.7.1` -> `3.0.2` 33 | - `source-map-loader` - `0.2.4` -> `2.0.0` 34 | - `spectron` - `5.0.0` -> `13.0.0` 35 | - `style-loader` - `0.23.1` -> `2.0.0` 36 | - `ts-loader` - `5.4.5` -> `8.0.12` 37 | - `ts-node` - `7.0.1` -> `9.1.1` 38 | - `typescript` - `3.7.2` - > `4.1.3` 39 | - `webpack` - `4.41.2` -> `5.11.0` 40 | - `webpack-cli` - `3.3.10` -> `4.3.0` 41 | - Moved `@types` packages from `dependencies` to `devDependencies` as those have no need to be included in production builds. 42 | - Commands of NPM scripts `dev` & `prod` to make them work with Webpack 5. 43 | - Migrated to ESLint from TSLint. 44 | - Updated prefix of internal paths from `@` to `_` to avoid confusions with scoped NPM packages. 45 | - Indentation for `.ts` files is now set as `2` spaces instead of `4`. 46 | - `electron-builder` settings: 47 | - `win`: 48 | - Enabled `asar`. _(turn it off if the executable built doesn't work)_ 49 | - Disabled one click installer. 50 | - Allowed custom installation directory in the installer built. 51 | - `mac`: 52 | - Changed build target back to `dmg`. 53 | - `buildVersion` is now being used as build number instead of just another parameter for semantic version number. 54 | - Updated section `Known issues` in `README`. 55 | 56 | ### Fixed 57 | - ESLint errors/warnings on `main.ts` & `renderer.tsx`. 58 | - `electron-builder` fails to build `dmg` on `macOS` (issue [electron-builder #3990])by upgrading the package version to `> 21.2.0`. 59 | 60 | ### Removed 61 | - NPM package `copy-pkg-json-webpack-plugin` as it doesn't work with Webpack 5 and seems not very well maintained. 62 | - NPM packages `acorn` & `ajv` from `devDependencies` as they're not being used in this boilerplate. 63 | - NPM packages `tslint` & `tslint-microsoft-contrib` as TSLint is now deprecated. 64 | 65 | ## [2.0.2] - 2019-12-02 66 | `v2.0.2` is a minor hotfix release fixed the documentation error and build error on `macOS Catalina(10.15+)`. 67 | 68 | ### Added 69 | - Extended README section `Getting started` with `npm start` command description. 70 | - README section `Known issue`. 71 | 72 | ### Changed 73 | - Minor version upgrades on package dependencies. 74 | - `macOS` build target to `pkg` from default `dmg` due to no 32-bit apps support from `macOS Catalina` that caused `electron-builder` fails to build `dmg` image on `macOS` prior to `electron-builder@21.2.0`. 75 | - _`pkg` build is unaffected and is used as a workaround for the current version prior to the major version upgrades on dependencies in next release. Related issue: [electron-builder #3990](https://github.com/electron-userland/electron-builder/issues/3990)_ 76 | 77 | ### Fixed 78 | - [Issue #2] - incorrect command `npm run install` to `npm install` in `README`. 79 | 80 | ## [2.0.1] - 2018-02-05 81 | `v2.0.1` is a minor hotfix release patched the `NODE_ENV` not set on Windows issue. 82 | 83 | ### Added 84 | - Package `cross-env` as `devDependencies`. 85 | - README section "Author". 86 | 87 | ### Fixed 88 | - NPM scripts won't set environment variables on Windows issue. 89 | 90 | ## 2.0.0 - 2018-02-04 91 | `v2.0.0` is a major release that most part of the boilerplate has been rewritten. 92 | 93 | ### Added 94 | - ESLint for code checking on Javascript files. 95 | - Airbnb's extensible `.eslintrc` package & its' peer dependencies. 96 | - `.eslintrc` that extends Airbnb's config and has customised rules configured. 97 | - _Rule `no-default-export` is set for JavaScript files to align with TypeScript._ 98 | - ESLint plugin `eslint-import-resolver-webpack` for ESLint to resolve path aliases set in Webpack config. 99 | - Webpack plugin `copy-pkg-json-webpack-plugin` to generate a `package.json` file and pack into Webpack's bundled package for production. 100 | - Build commands `build:mac` & `build:win` to package & build the installer of your Electron app for macOS & Windows using `electron-builder`. 101 | - README section "Building the installer for your Electron app" & sub-section "Extra options". 102 | 103 | ### Changed 104 | - Refactored Webpack config file to have `mainConfig` & `rendererConfig` cleaned up, and set mode by environment variable. 105 | - `.gitignore` to ignore folder `out/` which will be auto-generated during the build process. 106 | - README section "How does it work?" is now renamed to "Getting started" & completed the documentation of this section. 107 | - README section "Folder structure" to reflect the changes in `v2.0.0`. 108 | 109 | ### Fixed 110 | - CSS files fail to inject into views issue by setting Webpack to use `style-loader` alongside with `css-loader` to bundle the files in Webpack config file. 111 | - `baseUrl` in `tsconfig.json` points to root directory incorrectly issue. Corrected to current directory so VSCode can resolves the path aliases correctly. 112 | 113 | ### Removed 114 | - Redux & React-Redux related settings, including packages listed on `devDependencies`, path aliases & folders listed in folder structure. 115 | - Since Electron's built-in IPC & basic React states should be enough to get the works done, and most Electron apps which have their application logic runs on Electron's `main` process rather then `renderer` process actually don't need React-Redux, `redux` & `react-redux` are no longer included in this boilerplate. 116 | - Redux & React-Redux can still be used on this boilerplate by installing the package yourself. For details, please refer to the corresponding library's documents, there's no different than working on any other project which isn't based on this boilerplate. 117 | - Separated Webpack config files for `development` & `production` mode. 118 | 119 | [Unreleased]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/compare/v3.0.0...HEAD 120 | [2.0.1]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/compare/v2.0.0...v2.0.1 121 | [2.0.2]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/compare/v2.0.1...v2.0.2 122 | [3.0.0]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/compare/v2.0.2...v3.0.0 123 | 124 | [Issue #2]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/issues/2 125 | [electron-builder #3990]: https://github.com/electron-userland/electron-builder/issues/3990 126 | -------------------------------------------------------------------------------- /CHANGELOG_V4+.md: -------------------------------------------------------------------------------- 1 | # Changelog `v4+` 2 | All notable changes to this project on `v4+` will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 5 | 6 | ## [Unreleased] 7 | 8 | [Unreleased]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/compare/v4.1.3...HEAD 9 | 10 | ## [v4.1.3] - 2022-10-16 11 | ### Added 12 | - GitHub community standards & related workflows([#39](https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/pull/39)) 13 | - GitHub workflows for CI. 14 | - Jest config for GitHub Actions - `jest.config.ci.mjs`. 15 | - NPM scripts: 16 | - `lint` to run ESLint from CLI. 17 | - `jest` to replace the original `test` script with the following changes: 18 | - Removed `jest --clearCache` at the beginning as the updated Jest & ts-jest settings execute the dynamic import lines with no issue. 19 | - Disabled Node experimental warning message by setting `NODE_NO_WARNINGS=1`. 20 | - `jest-ci` to run Jest with CI config - `jest.config.ci.mjs`. 21 | 22 | ### Changed 23 | - File extension of Jest & Webpack config files to `mjs`. 24 | - Jest config to move `ts-jest` config to `transform` ([#40]) 25 | - NPM `test` script to run scripts `lint` then `jest`. 26 | - Rolled back the value of `moduleResolution` in `tsconfig` to `Node` (means `.js` file extension on relative imports is now __OPTIONAL__). 27 | - Enhanced function `pathsToESModuleNameMapper` in `jest.config.js` to return a less clumsy mapping object. 28 | 29 | --- 30 | 31 | ### Updates on package dependencies 32 | ### Update 33 | - Major version updates: 34 | - `@types/jest` - `28.1.6` -> `29.1.2` ([#44]) 35 | - `eslint-plugin-jest` - `26.8.2` -> `27.1.1` ([#44]) 36 | - `jest` - `28.1.3` -> `29.1.2` ([#44]) 37 | - `ts-jest` - `28.0.7` -> `29.0.3` ([#44]) 38 | - Minor & patch version updates: 39 | - `@types/react` - `18.0.17` -> `18.0.21` ([#44]) 40 | - `@typescript-eslint/eslint-plugin` & `@typescript-eslint/parser` - `5.33.0` -> `5.40.0` ([#44]) 41 | - `electron-builder` - `23.3.3` -> `23.6.0` ([#44]) 42 | - `eslint` - `8.22.0` -> `8.25.0` ([#44]) 43 | - `eslint-import-resolver-typescript` - `3.4.1` -> `3.5.1` ([#44]) 44 | - `eslint-plugin-react` - `7.30.1` -> `7.31.10` ([#44]) 45 | - `ts-loader` - `9.3.1` -> 9.4.1` ([#44]) 46 | - `typescript` - `4.7.4` -> `4.8.4` ([#44]) 47 | 48 | [#44]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/pull/44 49 | [#40]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/pull/40 50 | [v4.1.3]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/compare/v4.1.2...v4.1.3 51 | 52 | ## [v4.1.2] - 2022-08-15 53 | ### Added 54 | - Function `pathsToESModuleNameMapper` in `jest.config.js` to create the module mappings with ESM relative import with file extension (`.js`) syntax support for Jest from the path aliases set in `tsconfig`. 55 | 56 | ### Changed 57 | - Disable ESLint rule `import/no-extraneous-dependencies` on unit test files. 58 | - NPM script `test` now clear the cache for Jest before running the test and execute Jest with `NODE_OPTIONS=--experimental-vm-modules` flag to allow using dynamic import syntax. 59 | 60 | ### Fixed 61 | - Cannot find module issue reported by TypeScript server on relative imports in the unit test files after setting up native ES module support in [v4.1.0]. 62 | 63 | --- 64 | 65 | ### Updates on package dependencies 66 | ### Update 67 | - Minor & patch version updates: 68 | - `electron` - `20.0.1` -> `20.0.2` 69 | - `eslint` - `8.21.0` -> `8.22.0` 70 | - `eslint-import-resolver-typescript` - `3.4.0` -> `3.4.1` 71 | 72 | [v4.1.2]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/compare/v4.1.1...v4.1.2 73 | 74 | ## [v4.1.1] - 2022-08-10 75 | ### Fixed 76 | - Cannot find module issue reported by TypeScript server on relative imports after setting up native ES module support in [v4.1.0]. 77 | 78 | --- 79 | 80 | ### Updates on package dependencies 81 | ### Update 82 | - Minor & patch version updates: 83 | - `@types/react` - `18.0.15` -> `18.0.17` 84 | - `@typescript-eslint/eslint-plugin` & `@typescript-eslint/parser` - `5.32.0` -> `5.33.0` 85 | - `eslint-plugin-jest` - `26.7.0` -> `26.8.2` 86 | 87 | [v4.1.1]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/compare/v4.1.0...v4.1.1 88 | 89 | ## [v4.1.0] - 2022-08-07 90 | ### Added 91 | - `tsconfig.eslint.json` to avoid ESLint complains for file not being included in project provided. 92 | 93 | ### Changed 94 | - Migrated from deprecated `.eslintrc` (ESLint config with no file extension) to `CommonJS` file - `.eslintrc.cjs`, with the following changes on the configurations: 95 | - Different rules and plugins are now applied based on file types, allowing JavaScript files to be linted properly and only using plugins & rules needed on the targeted files. 96 | - Separated config to 4 objects - naming as `baseConfig`, `tsConfig`, `jestConfig`, and `specialConfig` respectively to maintain the readability on the pervious `.eslintrc`. 97 | - `eslint-plugin-import` is now properly configured for both JavaScript and TypeScript files. 98 | - `jest.config.js` & `webpack.config.js` are no longer ignored by ESLint. 99 | - Improved the readability of `webpack.config.js` by migrating to `webpack-merge` from using `lodash.deepClone()` for merging configuration objects. 100 | - Configured Node to resolve JavaScript files as ES modules (`"type": "module"` in `package.json`). 101 | - Refactored Jest and Webpack config files as ES modules. 102 | 103 | ### Fixed 104 | - Module import order warnings in most modules. 105 | - ESLint warnings & errors on `jest.config.js` & `webpack.config.js`. 106 | 107 | --- 108 | 109 | ### Updates on package dependencies 110 | ### Added 111 | - `eslint-import-resolver-typescript` *- Enhanced TypeScript support for ESLint `import` plugin* 112 | - `webpack-merge` *- Replaced the sections using `lodash.deepClone()` in `webpack.config.js`* 113 | 114 | ### Updated 115 | - Major version updates: 116 | - `electron` - `19.0.9` -> `20.0.1` 117 | - `tsconfig-paths-webpack-plugin` - `3.5.2` -> `4.0.0` 118 | - Minor & patch version updates: 119 | - `@typescript-eslint/eslint-plugin` & `@typescript-eslint/parser` - `5.30.7` -> `5.32.0` 120 | - `eslint` - `8.20.0` -> `8.21.0` 121 | - `eslint-plugin-jest` - `26.6.0` -> `26.7.0` 122 | - `electron-builder` - `23.1.0` -> `23.3.3` 123 | - `tsconfig-paths` - `4.0.0` -> `4.1.0` 124 | 125 | ### Removed 126 | - `eslint-import-resolver-webpack` *- Not being used in any part of the boilerplate* 127 | - `lodash` *- Replaced by `webpack-merge` for its' usage in `webpack.config.js`* 128 | 129 | [v4.1.0]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/compare/v4.0.0...v4.1.0 130 | 131 | ## [v4.0.0] - 2022-07-22 132 | ### Added 133 | - Jest as default unit testing framework, with sample test suite for `main`. 134 | - Integrated Electron preload pattern. 135 | - NPM scripts: 136 | - `watch-test` to run Jest in watch mode. 137 | - `next-rc`, `next-patch`, `next-minor` & `next-major` for quick package version number advance. 138 | 139 | ### Changed 140 | - Webpack will now take the module path alias from `tsconfig.json` and set it for you thanks to `tsconfig-paths-webpack-plugin`. Manually set up in Webpack config is no longer needed. 141 | - `tsconfig` now configured to use `ES2020` features, with module resolution set to `Node16` to match the NodeJS version used by Electron. 142 | - Migrated to the new `createRoot` API introduced in React `v18`. 143 | - Some APIs changed in Electron `main` entry script: 144 | - `mainWindow` now use `loadFile` API instead of `loadURL`. 145 | - Replaced `app.on('ready')` with `app.whenReady()` to align with syntax from [Electron official quick start guide](https://www.electronjs.org/docs/latest/tutorial/quick-start). 146 | - `electron-builder` now configured to build `universal` `dmg` for mac, 32 & 64 bit `exe` for Windows. 147 | - Moved `electron-builder`, Webpack & Webpack-related packages to `optionalDependencies`. 148 | - Revamped `README`. 149 | - __*Starting from this version, the maintenance schedule will be on a monthly update basis to keep the package dependencies up to date and keep the development going.*__ 150 | 151 | ### Fixed 152 | - Allow to use `import default` statement on non ES modules (e.g. React, lodash) by enabling `esModuleInterop` in `tsconfig`. [#14](https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/issues/14) 153 | 154 | ### Removed 155 | - Mocha in favour of Jest. 156 | - Spectron as it ahs been deprecated. *See - [Spectron Deprecation Notice](https://www.electronjs.org/blog/spectron-deprecation-notice)* 157 | 158 | --- 159 | 160 | ### Updates on package dependencies 161 | ### Added 162 | - `@types/jest`, `jest`, `ts-jest`, `eslint-plugin-jest` *- Jest support* 163 | - `eslint-config-airbnb-typescript` *- Enhance Airbnb's rules in TypeScript* 164 | - `ts-config-paths-webpack-plugin` *- Load `tsconfig` path alias into Webpack config* 165 | 166 | ### Updated 167 | - Major version updates: 168 | - `react` & `react-dom` - `17.0.1` -> `18.2.0` 169 | - `@types/react` - `17.0.0` -> `18.0.15` 170 | - `@types/react-dom` - `17.0.0` -> `18.0.6` 171 | - `@typescript-eslint/eslint-plugin` & `@typescript-eslint/parser` - `4.11.0` -> `5.30.7` 172 | - `electron` - `11.1.1` -> `19.0.9` 173 | - `eslint-config-airbnb` - `18.2.1` -> `19.0.4` 174 | - `copy-webpack-plugin` - `7.0.0` -> `11.0.0` 175 | - `css-loader` - `5.0.1` -> `6.7.1` 176 | - `electron-builder` - `22.9.1` -> `23.1.0` 177 | - `html-webpack-plugin` - `4.5.0` -> `5.5.0` 178 | - `style-loader` - `2.0.0` -> `3.3.1` 179 | - `ts-loader` - `8.0.12` -> `9.3.1` 180 | - `ts-config-paths` - `3.9.0` -> `4.0.0` 181 | - Minor & patch version updates: 182 | - `eslint-import-resolver-webpack` - `0.13.0` -> `0.13.2` 183 | - `eslint-plugin-import` - `2.22.1` -> `2.26.0` 184 | - `eslint-plugin-jsx-a11y` - `6.4.1` -> `6.6.1` 185 | - `eslint-plugin-react` - `7.21.5` -> `7.30.1` 186 | - `eslint-plugin-react-hoots` - `4.2.0` -> `4.6.0` 187 | - `lodash` - `4.17.20` -> `4.17.21` 188 | - `webpack` - `5.11.0` -> `5.73.0` 189 | - `webpack-cli` - `4.3.0` -> `4.10.0` 190 | 191 | ### Removed 192 | - `react-router`, `react-router-dom`, `@types/react-router`, `@types/react-router-dom` 193 | 194 | *\- Not being used in any part of the boilerplate* 195 | - `@types/mocha`, `mocha`, `ts-node` *- Replaced by `@types/jest`, `jest` & `ts-jest`* 196 | - `spectron` *- Deprecated package; No replacement* 197 | 198 | [v4.0.0]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/compare/v3.0.0...v4.0.0 199 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | We know that the general code of conduct document is boring, lengthy, and likely too formal that 99% of you wouldn't read it, so we're keeping it short and simple here: 4 | 5 | - Be kind, be nice, and be polite. Harassment, trolling, bullying or any insulting posts/comments are strictly prohibited. 6 | 7 | Project maintainers reserve the rights to remove, edit, or reject comments, commits, code, issues, and other contributions that are deemed inappropriate, threatening, offensive, or harmful. 8 | 9 | That's it. Happy coding. 10 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | Electron-React-Typescript-Webpack(ERTW) Boilerplate is one of Devtography's open-source projects that's under active development. As much as we want to make contributing to this project as easy and transparent as possible, the workflow is not quite there yet. Hopefully, this document makes the process for contributing clear and answers some questions that you might have. 4 | 5 | ## [Code of Conduct](CODE_OF_CONDUCT.md) 6 | 7 | We expect project participants to follow the basic principle that to be kind and respect others participating in this project. Read the [full text](CODE_OF_CONDUCT.md) if you got some time to kill. 8 | 9 | ## Open Development 10 | 11 | All work on ERTW Boilerplate happens directly on [GitHub](/). Both project maintainers and external contributors send pull requests which go through the same review process. 12 | 13 | ### `develop` is unsafe 14 | 15 | The default branch of this project is `develop`. As its name suggests, this is the branch where the development goes. We will do our best to keep `develop` in good shape, with tests passing at all times, but please bear in mind that unreleased changes are included in this branch, which from time to time might need some fixes before they make it into `master` a.k.a. the next release. 16 | 17 | ### Workflow and Pull Requests 18 | 19 | The maintainers will be monitoring for pull requests. When we get one, the CI will run some checks and tests on it first. If there's any failed checks/tests, we'd ask you to fix those first if that's needed. From here, the maintainers will will sign off on the changes and then merge the pull request. We'll do our best to provide updates and feedback throughout the process. 20 | 21 | _Before_ submitting a pull request, please make sure the following is done: 22 | 23 | 1. Fork the repo and create your own branch from `develop`. A guide on how to fork a repository: https://help.github.com/articles/fork-a-repo/ 24 | 25 | Open terminal (e.g. Terminal, iTerm, Git Bash or Git Shell) and type: 26 | 27 | ```sh-session 28 | $ git clone https://github.com//electron-react-typescript-webpack-boilerplate.git 29 | $ cd electron-react-typescript-webpack-boilerplate 30 | $ git checkout -b 31 | ``` 32 | 33 | Note: Replace `` with your GitHub username and `` with your branch name 34 | 35 | 1. Make sure you have `python` installed. Python is required by [node-gyp](https://github.com/nodejs/node-gyp) that is used when running `npm install`. 36 | 37 | To check your version of Python and ensure it's installed your can type: 38 | 39 | ```sh 40 | python --version 41 | 42 | # alternatively 43 | 44 | python3 --version 45 | ``` 46 | 47 | 1. Make sure your have a compatible version of `node` installed (As of September, 2022, `v16.x` is recommended). 48 | 49 | ```sh 50 | node -v 51 | ``` 52 | 53 | 1. Run `npm ci` (NOT `npm install`, we don't want unnecessary updates on `package.lock`). 54 | 55 | ```sh 56 | npm ci 57 | ``` 58 | 59 | 1. Call Webpack to build the bundles and check the code. `npm run dev` will run Webpack with watch mode to continuously update the bundles on file changed. 60 | 61 | ```sh 62 | npm run dev 63 | ``` 64 | 65 | 1. If you've added code that should be tested, add tests. You can use watch mode that continuously tests changed files to make your life easier. 66 | 67 | ```sh 68 | npm run watch-jest 69 | ``` 70 | 71 | 1. If you've made any changes to the usage of this boilerplate, or file structure, etc, update the documentation. 72 | 73 | 1. Ensure the test suite passes via `npm test`. 74 | 75 | 1. Ensure the app package can be built successfully with no issues via the following commands: 76 | 77 | ```sh-session 78 | $ npm run prod 79 | $ npm run build:win 80 | $ npm run build:mac 81 | ``` 82 | 83 | #### Changelog entries 84 | 85 | All changes that add a feature to or fix a bug in the boilerplate require a changelog entry containing the description of the change, and the number of and link to the pull request. Try to match the structure of the existing entries. 86 | 87 | You can add or edit the changelog entry in the GitHub web interface once you have opened the pull request and know the number and link to it. 88 | 89 | If you have changed / updated / removed any package dependency, a changelog entry is then require. Please make sure to alphabetically order your entry based on the package name. 90 | 91 | ## Bugs 92 | 93 | ### Where to Find Known Issues 94 | 95 | We will be using GitHub Issues for bugs. We will keep a close eye on this and try to make it clear when we have a fix in progress. Some notable/potential issues are also mentioned on [README](README.md). Before filling a new issue, try to make sure your problem doesn't already exist. 96 | 97 | ### Reporting New Issues 98 | 99 | The best way to get your bug fixed is to provide a reproducible test case. Please provide a public repository with a runnable example alongside your issue. 100 | 101 | ## Code Conventions 102 | 103 | - 2 spaces for indentation (no tabs). 104 | - 80 character line length is strongly preferred. 105 | - Prefer `'` over `"`. 106 | - ES6 syntax when possible. 107 | - Use [TypeScript](https://www.typescriptlang.org) 108 | - Avoid experimental APIs/features when possible. 109 | - Use semicolons; 110 | - Trailing commas, 111 | - Avd abbr wrds. 112 | 113 | ## License 114 | 115 | By contributing to ERTW Boilerplate, you agree that yur contributions will be licensed under its [MIT license](LICENSE). 116 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Devtography 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Electron-React-TypeScript-Webpack (ERTW) Boilerplate 2 | ![badge-ver] ![badge-node-ver] ![badge-license] 3 | 4 | [badge-ver]: https://img.shields.io/github/package-json/v/devtography/electron-react-typescript-webpack-boilerplate 5 | [badge-license]: https://img.shields.io/github/license/Devtography/electron-react-typescript-webpack-boilerplate 6 | [badge-node-ver]: https://img.shields.io/badge/node--lts-%3E%3D16-orange 7 | 8 | A boilerplate that let you instantly start working on your next [Electron] app 9 | project in [TypeScript] with no time wasted messing with the config files. 10 | 11 | - Ready to use [Electron] project template with [React], [Webpack] and [TypeScript] seamlessly integrated. 12 | - [ESLint] set up with TypeScript, Airbnb's rules, and [Jest] support. 13 | - [Jest] integrated and configured. 14 | - [`electron-builder`] for app packaging, with basic build config for Windows macOS included. 15 | - Clean, easy to read and alter config files. No config file is hidden behind yet another script! 16 | - Monthly maintenance to keep things up to date! 17 | 18 | *This boilerplate is tested on the latest macOS and Windows. If anything doesn't work, please [file an issue].* 19 | 20 | ### Maintenance schedule 21 | Starting from [`v4.0.0`], this project is set to receive regular maintenances. New releases will be published on monthly basis to keep the package dependencies, package configurations and APIs / syntax up to date. 22 | 23 | Maintenance work will begin on 1st of each month, and expect the new version to be released within the first week of the month. New features from different tools integrated in this boilerplate might not always be implemented at once, especially on experimental features. If you want any particular feature to be implemented, please [file an issue], or consider make a [new pull request]. 24 | 25 | ### Development plan 26 | - [ ] Develop a `create-react-app`-like NPX tool __!!! *(pending)*__ 27 | - [ ] Integrate another end-to-end testing framework to replace [Spectron] 28 | - [ ] Migrate to Webpack 5 `Asset Modules` __*(pending for `v4.2.0`)*__ 29 | - [ ] Integrate HMR & Webpack dev server 30 | - [ ] Introduce `v5.x-beta` releases based on `v4.x` with ESM support. 31 | 32 | --- 33 | 34 | ## 🚨 🚧 CAUTION 🚧 🚨 35 | - [Spectron] has officially been deprecated by the [Electron] team on February 1, 2022, thus, its' integration has also been dropped from this boilerplate on `v4+`. 36 | 37 | A replacement will be integrated in future version (pending for `v5`). Currently evaluating different options including [Playwright] and [WebdriverIO]. 38 | 39 | *See - [Spectron Deprecation Notice]* 40 | 41 | - `mocha` has been dropped and replaced by [Jest] on `v4+`. If you're using `mocha` as your unit testing framework, please reference to `package.json` from [`v3.0.0`]. 42 | 43 | - [ESLint] config file `.eslintrc.cjs` introduced in [`v4.1.0`] is written in CommonJS syntax on purpose. As of the release of [`v4.1.0`], ESLint has yet to support ES module for its' config file. __Converting the config file to ES module will result in ESLint not working.__ 44 | 45 | - ESM support introduced in [`v4.1.2`] has been reversed in [`v4.1.3`] as enabling ESM support has caused some incompatibilities with popular packages (e.g. `MUI`) without workarounds. A separate `v5.x-beta` branch will be released in the near future with ESM enabled by default. 46 | 47 | --- 48 | 49 | ## Getting started 50 | 1. Clone this repository with the following `git clone` command: 51 | 52 | ```sh 53 | git clone --depth 1 --branch master https://github.com/Devtography/electron-react-typescript-webpack-boilerplate.git 54 | ``` 55 | 56 | Alternatively, if you're hosting your Electron project on GitHub, click [`Use this template`] to create a new project. 57 | 58 | 2. Edit the following fields in `package.json` for your own project: 59 | 60 | ```json 61 | { 62 | "name": "your-project-name", 63 | "version": "whatever-you-like", 64 | "description": "your-own-description", 65 | "build": { 66 | "appId": "your-app-id", 67 | "productName": "your-product-name", 68 | "buildVersion": "your-build-number" 69 | }, 70 | "author": "who's-the-author?", 71 | "license": "if-you-don't-want-to-use-MIT", 72 | "repository": "type-and-link-of-your-repo", 73 | "bugs": "issue-page-of-your-repo", 74 | "homepage": "homepage-of-your-repo" 75 | } 76 | ``` 77 | 78 | 3. `npm install` to install the dependencies. 79 | 80 | *Please note that `optionalDependencies` should only be omitted on your CI/CD pipeline for unit testing. It's meant to save some bandwidth. You'll need all the packages listed for development.* 81 | 82 | Done! Now run `npm run dev` to start the Webpack in development and watch mode. It's time to start working on your project. 83 | 84 | Be aware that starting Webpack will only compile your files to `dist` folder but won't start the Electron app. Use `npm start` command to start your Electron app once the files are compiled. 85 | 86 | __*Starting from `v4.0.0`, you no longer need to manually config your module path alias in `webpack.config.js`. All module path alias set in `tsconfig.json` will be configured in Webpack automatically thanks to [`tsconfig-paths`] and [`tsconfig-paths-webpack-plugin`].*__ 87 | 88 | ## Build your Electron app package 89 | Different from the official [Electron quick start guide], this boilerplate uses [`electron-builder`] instead of [Electron Forge] to package your Electron app. 90 | 91 | By default, the build configuration in `package.json` is configured to build the mac universal package (for Apple Silicon & Intel based machines) and Windows `exe` installer (both 32 & 64 bit). You should not need to change anything in the build script other than supplying the app icon unless you need to sign your code/package or build for Linux. 92 | 93 | For code signing and notarization, or to build for Linux, please read [`electron-builder`'s document] for configuring the build script. 94 | 95 | To package your Electron app, run `npm run prod` to get your code compiled in `production` mode, then use `npm run build:(win|mac)` to build the package. 96 | 97 | ## Known issues 98 | - [`electron-builder`] packages the file into Electron's `asar` archive format by default. Based on past experiences with old Electron & `electron-builder` versions, this might lead to runtime error on Windows while launching the installed Electron app. 99 | 100 | One way to verify this issue is to build the mac package and see if your app runs fine on mac. If it's the case, you can override the `asar` archive option in the build configuration in `package.json` by adding `asar: false` in `win` section. 101 | 102 | This solution isn't ideal but since `asar` archiving is meant to improve performance of reading files if bundler like Webpack is not being used. The app packaging workflow defined in this boilerplate already uses Webpack to minify your code in `production` builds, so there shouldn't be any significant performance difference with `asar` archiving disabled. 103 | 104 | ## Contributing 105 | Development of Electron-React-Typescript-Webpack(ERTW) Boilerplate happens 100% open on GitHub, all contributions on bugfixes and improvements are welcomed. Read below to learn how you can take part in improving this boilerplate. 106 | 107 | ### [Code of Conduct](CODE_OF_CONDUCT.md) 108 | A simple Code of Conduct has been adopted and all project participants are expected to adhere to. Please read [the full text](CODE_OF_CONDUCT.md) so that you can understand what actions will and will not be tolerated. 109 | 110 | ### [Contributing Guide](CONTRIBUTING.md) 111 | Read the [contributing guide](CONTRIBUTING.md) to learn about the development process, how to propose bugfixes and improvements, and how to build and test your changes to ERTW Boilerplate. 112 | 113 | ### Donation 114 | Maintaining this project takes time, lots of cups of coffee, and I do it for free. Consider buy me some coffee via [GitHub Sponsors] or [PayPal]. 100% of your donation will fund my coffee buying budget for quality coffee beans from great roasters I know 😉 ☕️️ 115 | 116 | ## Project folders & files 117 | - `.github/` - GitHub repo config & GitHub Actions workflows 118 | - `dist/` - [Webpack] output location 119 | 120 | __Contents will be flushed automatically on execution of `npm run ` script.__ 121 | 122 | - `out/` - [`electron-builder`] output location 123 | 124 | - `public/` - Global static assets. 125 | - `index.html` - Template for `HTML Webpack Plugin` 126 | 127 | Update the value of `` tag to change the default window title. 128 | 129 | - `style.css` - `CSS` file location sample 130 | 131 | Not much defined in this file. You can either put your `CSS` settings here or use any other tools you prefer. 132 | 133 | - `src/` - Folder for all your source code 134 | - `main/` - For modules which run on the `main` process. 135 | - `main.ts` - [Electron] `main` process entry point 136 | 137 | - `preload` - Preload scripts go here 138 | - `ipc-api.ts` - APIs for IPC between `main` & `renderer` 139 | 140 | Consider convert this module into a collection of submodules if you have many APIs for IPC. See example as below: 141 | ```ts 142 | // ipc-api/index.ts 143 | import submoduleA from './submodule-a'; 144 | import submoduleB from './submodule-b'; 145 | 146 | export default { ...submoduleA, ...submoduleB }; 147 | 148 | // ipc-api/submodule-a.ts 149 | import { ipcRenderer } from 'electron'; 150 | 151 | function a { ipcRenderer.send('a'); } 152 | 153 | export default { a }; 154 | 155 | // ipc-api/submodule-b.ts 156 | import { ipcRenderer } from 'electron'; 157 | 158 | function b { ipcRenderer.send('b'); } 159 | 160 | export default { b }; 161 | ``` 162 | 163 | - `preload.ts` - [Electron] preload script entry point 164 | 165 | There should be no need to modify this file unless you want to use other key(s) for your IPC APIs. By default, all APIs defined in `ipc-api` module are exposed under key `ipcApi` in `contextBridge`. 166 | 167 | - `renderer/` - Where the frontend scripts stay 168 | - `App.tsx` - Root [React] component 169 | - `renderer.tsx` - [Electron] `renderer` process entry point 170 | 171 | *`public/style.css` imported here. Change it if you want.* 172 | 173 | - `types/` - Home for self-defined `.d.ts` files 174 | - `global.d.ts` - Extends global scope interfaces 175 | 176 | This file includes ambient declaration for calling the IPC APIs defined in `preload/ipc-api` from the `renderer`. Remember __NOT__ to remove this part, otherwise TypeScript will tell you `type not exist`. However, if you've opted to use a different key other than `ipcAPI` in the preload script, __DO__ remember to update this file to match your own settings. 177 | 178 | - `utils/` - Place to store the helper scripts 179 | - `node-env.ts` - Shortcut to determine `NODE` environment 180 | 181 | - `tests/` - Unit testing files location 182 | 183 | To avoid test files mixing up with the source code, [Jest] is configured to look for test file(s) within this folder only. 184 | 185 | File name of the test files can either be `[filename].test.tsx` or `[filename].spec.ts(x)`. `js(x)` can also be used for test files, but I assume you'd use TypeScript if you're using this boilerplate. 186 | 187 | - `main/main.spec.ts` - Sample test file for `src/main/main` 188 | - `utils/node-env.spec.ts` - Unit test for `src/utils/node-env` 189 | - `tsconfig.json` - TypeScript config file for `tests` module 190 | - `.eslintignore` - [ESLint] ignore file 191 | - `.eslintrc.cjs` - [ESLint] config file 192 | 193 | Configured to use Airbnb's rules with [TypeScript] supported, and rules for [Jest] applied. 194 | 195 | - `.gitignore` - Git ignore file 196 | - `CHANGELOG_PRE_V4.md` - Changelog of this boilerplate prior to `v4.0.0` 197 | - `CHANGELOG_V4+.md` - Changelog of this boilerplate from `v4.0.0` onwards 198 | - `CODE_OF_CONDUCT.md` 199 | - `CONTRIBUTING.md` - Contribution guide 200 | - `jest.config.ci.mjs` - [Jest] config file for GitHub Actions 201 | - `jest.config.mjs` - [Jest] config file 202 | - `LICENSE` - MIT license 203 | - `package-lock.json` 204 | - `package.json` 205 | 206 | Includes basic build config for `electron-builder`. It's likely that you'll have to personalise the build config when it comes to the time you're about to release your app. Please read [`electron-builder`'s document] for the build config setup guides. 207 | 208 | - `README.md` 209 | - `tsconfig.eslint.json` - [TypeScript] config file consume by [ESLint]. 210 | - `tsconfig.json` - [TypeScript] config file 211 | 212 | Module path aliases are configured here. [Jest] & [Webpack] will pick up the alias settings here to config their own. No need to manually config in Jest & Webpack again. 213 | 214 | - `webpack.config.json` - [Webpack] config file 215 | 216 | Includes configurations targetting `electron-main`, `electron-preload`, and `electron-renderer` respectively. 217 | 218 | ## Author 219 | [Wing Chau](https://github.com/iamWing) [@Devtography](https://github.com/Devtography) 220 | 221 | ## License 222 | Electron React TypeScript Webpack Boilerplate is open source software 223 | [licensed as MIT](LICENSE). 224 | 225 | [Electron]: https://www.electronjs.org 226 | [React]: https://reactjs.org 227 | [Webpack]: https://webpack.js.org 228 | [TypeScript]: https://www.typescriptlang.org 229 | [ESLint]: http://eslint.org 230 | [Jest]: https://jestjs.io 231 | [`electron-builder`]: https://github.com/electron-userland/electron-builder 232 | [file an issue]: https://www.electronjs.org 233 | [new pull request]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/compare 234 | [Spectron]: https://github.com/electron-userland/spectron 235 | [ts-jest]: https://github.com/kulshekhar/ts-jest 236 | [Playwright]: https://playwright.dev 237 | [WebdriverIO]: https://webdriver.io 238 | [Spectron Deprecation Notice]: https://www.electronjs.org/blog/spectron-deprecation-notice 239 | [`Use this template`]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/generate 240 | [`tsconfig-paths`]: https://github.com/dividab/tsconfig-paths 241 | [`tsconfig-paths-webpack-plugin`]: https://github.com/dividab/tsconfig-paths-webpack-plugin 242 | [Electron quick start guide]: https://www.electronjs.org/docs/latest/tutorial/quick-start 243 | [Electron Forge]: https://github.com/electron-userland/electron-forge 244 | [`electron-builder`'s document]: https://www.electron.build 245 | [GitHub Sponsors]: https://github.com/sponsors/iamWing 246 | [PayPal]: https://paypal.me/iamWing0w0 247 | 248 | [`v3.0.0`]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/releases/tag/v3.0.0 249 | [`v4.0.0`]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/releases/tag/v4.0.0 250 | [`v4.1.0`]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/releases/tag/v4.1.0 251 | [`v4.1.2`]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/releases/tag/v4.1.2 252 | [`v4.1.3`]: https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/releases/tag/v4.1.3 253 | -------------------------------------------------------------------------------- /jest.config.ci.mjs: -------------------------------------------------------------------------------- 1 | import baseConfig from './jest.config.mjs'; 2 | 3 | /** @type {import('jest').Config} */ 4 | export default { 5 | ...baseConfig, 6 | coverageReporters: ['json'], 7 | reporters: ['default', 'github-actions'], 8 | }; 9 | -------------------------------------------------------------------------------- /jest.config.mjs: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'module'; 2 | import { pathsToModuleNameMapper } from 'ts-jest'; 3 | 4 | const require = createRequire(import.meta.url); 5 | const { compilerOptions } = require('./tsconfig.json'); 6 | 7 | /** 8 | * Enhance the Jest path mappings map returned from `pathsModuleNameMapper` 9 | * to support ES modules import syntax in TypeScript. 10 | * 11 | * @returns Jest path mappings map. 12 | */ 13 | function pathsToESModuleNameMapper() { 14 | const map = pathsToModuleNameMapper( 15 | compilerOptions.paths, 16 | { prefix: '<rootDir>' }, 17 | ); 18 | const esmMap = {}; 19 | 20 | Object.entries(map).forEach((entry) => { 21 | const [key, val] = entry; 22 | 23 | if (/.*\(\.\*\)\$$/.test(key)) { 24 | // eslint-disable-next-line prefer-template 25 | const convertedKey = key.substring(0, key.length - 2) 26 | + '[^\\.js])(\\.js)?$'; 27 | esmMap[convertedKey] = val; 28 | } 29 | }); 30 | 31 | // Append the mapping for relative paths without path alias. 32 | esmMap['^(\\.{1,2}/.*)\\.js$'] = '$1'; 33 | 34 | return esmMap; 35 | } 36 | 37 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 38 | export default { 39 | testEnvironment: 'node', 40 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], 41 | moduleNameMapper: pathsToESModuleNameMapper(), 42 | modulePathIgnorePatterns: [ 43 | '<rootDir>/dist', 44 | '<rootDir>/node_modules', 45 | '<rootDir>/out', 46 | ], 47 | transform: { 48 | '^.+\\.(ts|tsx)$': [ 49 | 'ts-jest', 50 | { 51 | tsconfig: 'tsconfig.json', 52 | }, 53 | ], 54 | }, 55 | testMatch: [ 56 | '**/tests/**/*.(spec|test).([jt]s?(x))', 57 | ], 58 | collectCoverage: true, 59 | verbose: true, 60 | }; 61 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "electron-react-typescript-webpack-boilerplate", 3 | "version": "4.1.3", 4 | "description": "Pre-configured boilerplate for Electron + React + TypeScript", 5 | "main": "./dist/main.bundle.js", 6 | "scripts": { 7 | "start": "electron ./dist/main.bundle.js", 8 | "dev": "rimraf dist && cross-env NODE_ENV=development webpack --watch --progress --color", 9 | "prod": "rimraf dist && cross-env NODE_ENV=production webpack --progress --color", 10 | "jest": "cross-env NODE_ENV=test NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 jest", 11 | "jest-ci": "npm run jest -- --config jest.config.ci.mjs", 12 | "watch-jest": "npm run jest -- --watchAll", 13 | "lint": "eslint . --cache --ext js,jsx,cjs,mjs,ts,tsx", 14 | "test": "npm run lint && npm run jest", 15 | "next-rc": "npm --no-git-tag-version version prerelease --preid=rc", 16 | "next-patch": "npm --no-git-tag-version version patch", 17 | "next-minor": "npm --no-git-tag-version version minor", 18 | "next-major": "npm --no-git-tag-version version major", 19 | "build:win": "electron-builder build --win", 20 | "build:mac": "electron-builder build --mac" 21 | }, 22 | "build": { 23 | "appId": "com.devtography.electron_boilerplate", 24 | "productName": "Electron+React+TypeScript Boilerplate", 25 | "directories": { 26 | "app": "./dist/", 27 | "output": "./out/" 28 | }, 29 | "mac": { 30 | "target": { 31 | "target": "dmg", 32 | "arch": "universal" 33 | } 34 | }, 35 | "win": { 36 | "target": { 37 | "target": "nsis", 38 | "arch": [ 39 | "x64", 40 | "ia32" 41 | ] 42 | } 43 | }, 44 | "nsis": { 45 | "oneClick": false, 46 | "allowToChangeInstallationDirectory": true 47 | }, 48 | "buildVersion": "1" 49 | }, 50 | "author": "Wing Chau @Devtography", 51 | "license": "MIT", 52 | "dependencies": { 53 | "react": "^18.2.0", 54 | "react-dom": "^18.2.0" 55 | }, 56 | "devDependencies": { 57 | "@types/jest": "^29.1.2", 58 | "@types/react": "^18.0.21", 59 | "@types/react-dom": "^18.0.6", 60 | "@typescript-eslint/eslint-plugin": "^5.40.0", 61 | "@typescript-eslint/parser": "^5.40.0", 62 | "cross-env": "^7.0.3", 63 | "electron": "^21.1.0", 64 | "eslint": "^8.25.0", 65 | "eslint-config-airbnb": "^19.0.4", 66 | "eslint-config-airbnb-typescript": "^17.0.0", 67 | "eslint-import-resolver-typescript": "^3.5.1", 68 | "eslint-plugin-import": "^2.26.0", 69 | "eslint-plugin-jest": "^27.1.1", 70 | "eslint-plugin-jsx-a11y": "^6.6.1", 71 | "eslint-plugin-react": "^7.31.10", 72 | "eslint-plugin-react-hooks": "^4.6.0", 73 | "jest": "^29.1.2", 74 | "ts-jest": "^29.0.3", 75 | "typescript": "^4.8.4" 76 | }, 77 | "optionalDependencies": { 78 | "copy-webpack-plugin": "^11.0.0", 79 | "css-loader": "^6.7.1", 80 | "electron-builder": "^23.6.0", 81 | "file-loader": "^6.2.0", 82 | "html-webpack-plugin": "^5.5.0", 83 | "rimraf": "^3.0.2", 84 | "style-loader": "^3.3.1", 85 | "ts-loader": "^9.4.1", 86 | "tsconfig-paths": "^4.1.0", 87 | "tsconfig-paths-webpack-plugin": "^4.0.0", 88 | "webpack": "^5.74.0", 89 | "webpack-cli": "^4.10.0", 90 | "webpack-merge": "^5.8.0" 91 | }, 92 | "repository": { 93 | "type": "git", 94 | "url": "git+https://github.com/Devtography/electron-react-typescript-webpack-boilerplate" 95 | }, 96 | "bugs": { 97 | "url": "https://github.com/Devtography/electron-react-typescript-webpack-boilerplate/issues" 98 | }, 99 | "homepage": "https://github.com/Devtography/electron-react-typescript-webpack-boilerplate#readme" 100 | } 101 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html> 3 | 4 | <head> 5 | <meta charset="utf-8"> 6 | <title>Hello World! 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /public/style.css: -------------------------------------------------------------------------------- 1 | .app { 2 | color: grey; 3 | } 4 | -------------------------------------------------------------------------------- /src/main/main.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Entry point of the Election app. 3 | */ 4 | import * as path from 'path'; 5 | // eslint-disable-next-line import/no-extraneous-dependencies 6 | import { BrowserWindow, app, ipcMain } from 'electron'; 7 | import * as nodeEnv from '_utils/node-env'; 8 | 9 | let mainWindow: Electron.BrowserWindow | undefined; 10 | 11 | function createWindow() { 12 | // Create the browser window. 13 | mainWindow = new BrowserWindow({ 14 | height: 600, 15 | width: 800, 16 | webPreferences: { 17 | devTools: nodeEnv.dev, 18 | preload: path.join(__dirname, './preload.bundle.js'), 19 | webSecurity: nodeEnv.prod, 20 | }, 21 | }); 22 | 23 | // and load the index.html of the app. 24 | mainWindow.loadFile('index.html').finally(() => { /* no action */ }); 25 | 26 | // Emitted when the window is closed. 27 | mainWindow.on('closed', () => { 28 | // Dereference the window object, usually you would store windows 29 | // in an array if your app supports multi windows, this is the time 30 | // when you should delete the corresponding element. 31 | mainWindow = undefined; 32 | }); 33 | } 34 | 35 | // This method will be called when Electron has finished 36 | // initialization and is ready to create browser windows. 37 | // Some APIs can only be used after this event occurs. 38 | app.whenReady().then(() => { 39 | if (nodeEnv.dev || nodeEnv.prod) createWindow(); 40 | 41 | app.on('activate', () => { 42 | if (BrowserWindow.getAllWindows.length === 0) createWindow(); 43 | }); 44 | }).finally(() => { /* no action */ }); 45 | 46 | // Quit when all windows are closed, except on macOS. There, it's common 47 | // for applications and their menu bar to stay active until the user quits 48 | // explicitly with Cmd + Q. 49 | app.on('window-all-closed', () => { 50 | if (process.platform !== 'darwin') app.quit(); 51 | }); 52 | 53 | ipcMain.on('renderer-ready', () => { 54 | // eslint-disable-next-line no-console 55 | console.log('Renderer is ready.'); 56 | }); 57 | 58 | // In this file you can include the rest of your app"s specific main process 59 | // code. You can also put them in separate files and require them here. 60 | 61 | // eslint-disable-next-line import/prefer-default-export 62 | export const exportedForTests = nodeEnv.test ? { createWindow } : undefined; 63 | -------------------------------------------------------------------------------- /src/preload/ipc-api.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-extraneous-dependencies 2 | import { ipcRenderer } from 'electron'; 3 | 4 | /** Notify main the renderer is ready. */ 5 | function rendererReady() { 6 | ipcRenderer.send('renderer-ready'); 7 | } 8 | 9 | export default { rendererReady }; 10 | -------------------------------------------------------------------------------- /src/preload/preload.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-extraneous-dependencies 2 | import { contextBridge } from 'electron'; 3 | import ipcAPI from '_preload/ipc-api'; 4 | 5 | contextBridge.exposeInMainWorld('ipcAPI', ipcAPI); 6 | -------------------------------------------------------------------------------- /src/renderer/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react'; 2 | 3 | function App(): JSX.Element { 4 | useEffect(() => { 5 | window.ipcAPI?.rendererReady(); 6 | }, []); 7 | 8 | return ( 9 |
10 |

Welcome to React, Electron and TypeScript

11 |

Hello

12 |
13 | ); 14 | } 15 | 16 | export default App; 17 | -------------------------------------------------------------------------------- /src/renderer/renderer.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * React renderer. 3 | */ 4 | // Import the styles here to process them with webpack 5 | import '_public/style.css'; 6 | 7 | import * as React from 'react'; 8 | import { createRoot } from 'react-dom/client'; 9 | import App from '_renderer/App'; 10 | 11 | const container = document.getElementById('app'); 12 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 13 | const root = createRoot(container!); 14 | root.render(); 15 | -------------------------------------------------------------------------------- /src/types/global.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | interface Window { 3 | /** APIs for Electron IPC */ 4 | ipcAPI?: typeof import('_preload/ipc-api').default 5 | } 6 | } 7 | 8 | // Makes TS sees this as an external modules so we can extend the global scope. 9 | export { }; 10 | -------------------------------------------------------------------------------- /src/utils/node-env.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Predefined NODE_ENV values 3 | */ 4 | 5 | /** `NODE_ENV=production` */ 6 | export const prod = process.env.NODE_ENV === 'production'; 7 | 8 | /** `NODE_ENV=development` */ 9 | export const dev = process.env.NODE_ENV === 'development'; 10 | 11 | /** `NODE_ENV=test` */ 12 | export const test = process.env.NODE_ENV === 'test'; 13 | -------------------------------------------------------------------------------- /tests/main/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { jest } from '@jest/globals'; 2 | import { BrowserWindow } from 'electron'; 3 | import { exportedForTests } from '_main/main'; 4 | 5 | jest.mock('electron', () => ({ 6 | app: { 7 | on: jest.fn(), 8 | whenReady: jest.fn(() => Promise.resolve()), 9 | }, 10 | ipcMain: { on: jest.fn() }, 11 | BrowserWindow: jest.fn().mockImplementation(() => ({ 12 | loadFile: jest.fn(() => Promise.resolve()), 13 | on: jest.fn(), 14 | })), 15 | })); 16 | 17 | test('Private props exported for unit tests', () => { 18 | expect(exportedForTests).toBeDefined(); 19 | }); 20 | 21 | test('func createWindow()', () => { 22 | const { createWindow } = exportedForTests!; 23 | 24 | createWindow(); 25 | expect(BrowserWindow).toHaveBeenCalledTimes(1); 26 | }); 27 | -------------------------------------------------------------------------------- /tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true 5 | }, 6 | "include": ["./**/*"] 7 | } -------------------------------------------------------------------------------- /tests/utils/node-env.spec.ts: -------------------------------------------------------------------------------- 1 | import { jest } from '@jest/globals'; 2 | 3 | test('NODE_ENV=test', async () => { 4 | process.env.NODE_ENV = 'test'; 5 | jest.resetModules(); 6 | 7 | const nodeEnv = await import('_utils/node-env'); 8 | 9 | expect(nodeEnv.test).toBeTruthy(); 10 | expect(nodeEnv.dev).toBeFalsy(); 11 | expect(nodeEnv.prod).toBeFalsy(); 12 | }); 13 | 14 | test('NODE_ENV=development', async () => { 15 | process.env.NODE_ENV = 'development'; 16 | jest.resetModules(); 17 | 18 | const nodeEnv = await import('_utils/node-env'); 19 | 20 | expect(nodeEnv.dev).toBeTruthy(); 21 | expect(nodeEnv.prod).toBeFalsy(); 22 | expect(nodeEnv.test).toBeFalsy(); 23 | }); 24 | 25 | test('NODE_ENV=production', async () => { 26 | process.env.NODE_ENV = 'production'; 27 | jest.resetModules(); 28 | 29 | const nodeEnv = await import('_utils/node-env'); 30 | 31 | expect(nodeEnv.prod).toBeTruthy(); 32 | expect(nodeEnv.dev).toBeFalsy(); 33 | expect(nodeEnv.test).toBeFalsy(); 34 | }); 35 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true 5 | }, 6 | "include": [ 7 | "src/**/*", 8 | "tests/**/*", 9 | ".eslintrc.cjs", 10 | "**/*.config.js", 11 | "**/*.config.cjs", 12 | "**/*.config.mjs", 13 | "**/*.config.*.js", 14 | "**/*.config.*.cjs", 15 | "**/*.config.*.mjs" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "baseUrl": ".", 5 | "module": "ES2020", 6 | "moduleResolution": "Node", 7 | "paths": { 8 | "_/*": ["src/*"], 9 | "_public/*": ["public/*"], 10 | "_main/*": ["src/main/*"], 11 | "_preload/*": ["src/preload/*"], 12 | "_renderer/*": ["src/renderer/*"], 13 | "_types/*": ["src/types/*"], 14 | "_utils/*": ["src/utils/*"], 15 | "_tests/*": ["tests/*"] 16 | }, 17 | "typeRoots": [ 18 | "./node_modules/@types", 19 | "./src/types" 20 | ], 21 | "sourceMap": true, 22 | "allowSyntheticDefaultImports": true, 23 | "esModuleInterop": true, 24 | "jsx": "react", 25 | "target": "ES2020" 26 | }, 27 | "include": ["src/**/*"] 28 | } 29 | -------------------------------------------------------------------------------- /webpack.config.mjs: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { fileURLToPath } from 'url'; 3 | import CopyPlugin from 'copy-webpack-plugin'; 4 | import HtmlWebpackPlugin from 'html-webpack-plugin'; 5 | import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin'; 6 | import webpack from 'webpack'; 7 | import { merge } from 'webpack-merge'; 8 | 9 | /* eslint-disable no-underscore-dangle */ 10 | const __filename = fileURLToPath(import.meta.url); 11 | const __dirname = path.dirname(__filename); 12 | /* eslint-enable */ 13 | 14 | const isEnvProduction = process.env.NODE_ENV === 'production'; 15 | const isEnvDevelopment = process.env.NODE_ENV === 'development'; 16 | 17 | const commonConfig = { 18 | devtool: isEnvDevelopment ? 'source-map' : false, 19 | mode: isEnvProduction ? 'production' : 'development', 20 | output: { path: path.join(__dirname, 'dist') }, 21 | node: { __dirname: false, __filename: false }, 22 | plugins: [ 23 | new webpack.NormalModuleReplacementPlugin(/^\S+\/\S+\.js$/, (resource) => { 24 | // eslint-disable-next-line no-param-reassign 25 | resource.request = resource.request.replace(/\.js$/, ''); 26 | }), 27 | ], 28 | resolve: { 29 | extensions: ['.js', '.json', '.ts', '.tsx'], 30 | plugins: [new TsconfigPathsPlugin({ 31 | configFile: './tsconfig.json', 32 | extensions: ['.js', '.json', '.ts', '.tsx'], 33 | })], 34 | }, 35 | module: { 36 | rules: [ 37 | { 38 | test: /\.(ts|tsx)$/, 39 | exclude: /node_modules/, 40 | loader: 'ts-loader', 41 | }, 42 | { 43 | test: /\.(scss|css)$/, 44 | use: ['style-loader', 'css-loader'], 45 | }, 46 | { 47 | test: /\.(jpg|png|svg|ico|icns)$/, 48 | loader: 'file-loader', 49 | options: { 50 | name: '[path][name].[ext]', 51 | }, 52 | }, 53 | ], 54 | }, 55 | }; 56 | 57 | const mainConfig = merge(commonConfig, { 58 | entry: './src/main/main.ts', 59 | target: 'electron-main', 60 | output: { filename: 'main.bundle.js' }, 61 | plugins: [ 62 | new CopyPlugin({ 63 | patterns: [ 64 | { 65 | from: 'package.json', 66 | to: 'package.json', 67 | transform: (content, _path) => { 68 | const jsonContent = JSON.parse(content); 69 | const electronVersion = jsonContent.devDependencies.electron; 70 | 71 | delete jsonContent.devDependencies; 72 | delete jsonContent.optionalDependencies; 73 | delete jsonContent.scripts; 74 | delete jsonContent.build; 75 | 76 | jsonContent.main = './main.bundle.js'; 77 | jsonContent.scripts = { start: 'electron ./main.bundle.js' }; 78 | jsonContent.devDependencies = { electron: electronVersion }; 79 | 80 | return JSON.stringify(jsonContent, undefined, 2); 81 | }, 82 | }, 83 | ], 84 | }), 85 | ], 86 | }); 87 | 88 | const preloadConfig = merge(commonConfig, { 89 | entry: './src/preload/preload.ts', 90 | target: 'electron-preload', 91 | output: { filename: 'preload.bundle.js' }, 92 | }); 93 | 94 | const rendererConfig = merge(commonConfig, { 95 | entry: './src/renderer/renderer.tsx', 96 | target: 'electron-renderer', 97 | output: { filename: 'renderer.bundle.js' }, 98 | plugins: [ 99 | new HtmlWebpackPlugin({ 100 | template: path.resolve(__dirname, './public/index.html'), 101 | }), 102 | ], 103 | }); 104 | 105 | export default [mainConfig, preloadConfig, rendererConfig]; 106 | --------------------------------------------------------------------------------