introduce

In this article, we will introduce how to build the Electron project using the same framework we created in Webpack4+ Node +typescript+hotReload.

  git clone [email protected]:spcBackToLife/node-webpack4-ts-demo.git
Copy the code

The construction of the basic framework mainly includes the following parts, and basically each part is a separate article:

  • basisnodeEnvironment building:webpack4 + node + typescript
  • ElectronIntegration: single window + main process, render process in dev, PROd environmentwebpackTo deal with.
  • Reactintegration
  • MobxIntegration (because redux is heavy and DVA is troublesome, Mobx is more suitable for react state management)
  • ElectronIntegration: Multi-window + window rendering processwebpackTo deal with.
  • Data cache and storage service management
  • Application basic function service design: screen recording, screen capture
  • Application integration tripartite environment design: Python environment
  • applicationwebviewInjection JS design
  • Run Log Integration

ElectronIntegration – Single window + main process, render process in dev, PROd environmentwebpackTo deal with

For the Electron base integration, see: Introduction to Electron. This is no longer a chore. Just do it.

  1. Add the Electron dependency

    ELECTRON_MIRROR=https://npm.taobao.org/mirrors/electron/ yarn add [email protected] - DCopy the code
  2. SRC create main-process, render-process folders and place main.ts in main-process.

    • Main-process # Main process folder
    • Render – Process # render process folder

For more information about the main process and render process, see article: Electron- Main process and Render Process It is highly recommended to read through this concept before reading the rest of this article, unless you are very familiar with Electron and already know the main process and render process.

  1. SRC Create an index. HTML file

    
            
    <html>
        <head>
            <meta charset="utf-8">
            <title>electron-sprout</title>
            <script>
                (
                    function() {
                        if(! process.env.HOT) {// In the production environment, load the packaged style.css, and the CSS is handled in the webpack.
                            const link = document.createElement('link');
                            link.ref = 'stylesheet';
                            link.href = '.. /dist/style.css'; }})</script>
        </head>
        <body>
            <div id="root">I'm going to put hellowold here, so I'm going to clear it when I integrate react</div>
        </body>
        <script>
            {   
                const scripts = [];
                const port = process.env.PORT || 1212;
                // In the development environment, load js from webpack-dev server.
                // In production, load the packaged JS
                scripts.push(
                (process.env.HOT)
                    ? 'http://localhost:' + port + '/dist/renderer.dev.js'
                    : '.. /dist/renderer.prod.js'
                );
                // Write the js to the page to load.
                document.write(
                scripts
                    .map(script= > `<script defer src="${script}"><\/script>`)
                    .join(' ')); }</script>
    </html>
    Copy the code
  2. Create main-window.ts in main-process:

    import { BrowserWindow } from 'electron';
    
    export const createWindow = (a)= > {
      const win = new BrowserWindow({
        show: true,
        width: 890,
        height: 556,
        webgl: true,
        frame: true,
        transparent: false,
        webPreferences: {
          webSecurity: true,
          allowRunningInsecureContent: false,
          nativeWindowOpen: false,
          nodeIntegration: true,}}); win.webContents.openDevTools(); win.loadURL(`file://${__dirname}/.. /index.html`);
    };
    
    Copy the code

As you can see in the code above: We use the BrowserWindow provided by Electron to open a system window similar to a browser TAB that can load a web page or local file index.html using a loadURL. For details about the API, see the Electron website

  1. Remove all the test code from main.ts and replace it with the following:

    
    import { app } from 'electron';
    import { createWindow } from './main-window';
    
    app.on('ready'.async () => {
      createWindow(); // Create a system application window
    });
    
    app.on('window-all-closed'.(a)= > app.quit()); Exit the application when all Windows are closed
    
    Copy the code
  2. Configure webPack to handle main process, render process JS.

For more information about main process and render process, see article: Electron- Main Process, Render Process

First let’s configure a basic webpack, used for processing, TS \js\ CSS: webpack.config.base.js, about webpack related content, go to learn ha, didn’t write an article, don’t learn according to me this match also line, I match also not professional, ha ha, can use.

Create a new folder config/webpack and create a new file webpack.config.base.js below

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');

const isProd = process.env.NODE_ENV === 'production';
const cssLoader = {
  loader: 'css-loader'.options: {
    modules: true.importLoaders: 1.localIdentName: '[local]__[hash:6]',}};// const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
  target: 'electron-main'.This will be mentioned in the main and renderer articles, see the article at the beginning of point 6.
  resolve: {
    // changed from extensions: [".js", ".jsx"]
    extensions: ['.ts'.'.tsx'.'.js'.'.jsx'].// The type of file to process
  },
  module: {
    rules: [{test: /\.scss$/.// CSS Loader configuration
        use: [
          isProd ? MiniCssExtractPlugin.loader : 'style-loader',
          cssLoader,
          'sass-loader',]}, {test: /\.tsx? $/./ / TSX composite processing
        exclude: /node_modules/.use: [{loader: 'babel-loader'.options: {
              cacheDirectory: true,}},/ / {
          // loader: 'awesome-typescript-loader',
          // },],},// Common Image Formats
      {
        test: / \. (? :ico|gif|png|jpg|jpeg|webp)$/.// Image path processing
        use: 'url-loader',},// addition - add source-map support
      { enforce: 'pre'.test: /\.js$/.loader: 'source-map-loader' }, // Source-map error reported],},node: {
    __dirname: false.// Handle the error in the path of the dirname filename variable after packaging
    __filename: false,},devtool: 'source-map'.plugins: [
    new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/), // Using the moment component, use this to reduce the size of the moment library as part of the infrastructure
    new webpack.NamedModulesPlugin(), // Used to display the relative path of modules when hot Module reload (HMR) is enabled]};Copy the code

Let’s deal with the main process js. New config files/webpack webpack. Config. Main. Prod. Babel. Js (about why want to distinguish between the main process, rendering process with js respectively, the article 6 points mentioned in ha.) , because the main process development environment does not need to do processing, it can be directly executed, so only the production environment needs to process JS.

const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const TerserPlugin = require('terser-webpack-plugin');
const baseConfig = require('./webpack.config.base');

module.exports = merge.smart(baseConfig, {
  devtool: 'source-map'.mode: 'production'.entry: './src/main.ts'.output: {
    path: path.join(__dirname, '.. /.. / '),
    filename: './dist/main.prod.js',},optimization: {
    minimizer: process.env.E2E_BUILD
      ? []
      : [
        new TerserPlugin({  / / compressed Javascript
          parallel: true.sourceMap: true.cache: true,})]},plugins: [
    new webpack.EnvironmentPlugin({
      NODE_ENV: 'production',})]});Copy the code

Then, we will deal with rendering process JS, in the development environment, in order to change the code can automatically refresh the page, hot update, we use webpack-dev-server to do the processing, so the processing of rendering process JS will be divided into development environment and generation environment, there are different configuration files. Let’s start by generating the development environment. The new config file/webpack webpack. Config. The renderer. Dev. Babel. Js


const path = require('path');
const merge = require('webpack-merge');
const { spawn } = require('child_process');
const webpack = require('webpack');
const baseConfig = require('./webpack.config.base');

const port = process.env.PORT || 1212;
const publicPath = `http://localhost:${port}/dist`;
module.exports = merge.smart(baseConfig, {
  devtool: 'inline-source-map'.mode: 'development'.target: 'electron-renderer'.entry: {
    renderer: [
      require.resolve('.. /.. /src/render-process/index.tsx'),
      // 'react-hot-loader/patch', // start when react is integrated
      `webpack-dev-server/client? http://localhost:${port}/ `.'webpack/hot/only-dev-server',]},output: {
    publicPath: `http://localhost:${port}/dist`.filename: '[name].dev.js',},plugins: [
    new webpack.NamedModulesPlugin(), // Used to display the relative path of the module when starting HMR
    new webpack.HotModuleReplacementPlugin(), // Hot Module replacement A hot replacement for the boot module
    new webpack.NoEmitOnErrorsPlugin(),
    new webpack.EnvironmentPlugin({
      NODE_ENV: 'development',}).new webpack.LoaderOptionsPlugin({
      debug: true,})],devServer: {
    port,
    publicPath,
    compress: true.noInfo: true.stats: 'errors-only'.inline: true.lazy: false.hot: true.headers: { 'Access-Control-Allow-Origin': The '*' },
    contentBase: path.join(__dirname, 'dist'),
    watchOptions: {
      aggregateTimeout: 300.ignored: /node_modules/.poll: 100,},historyApiFallback: {
      verbose: true.disableDotRule: false,
    },
    before() {
      if (process.env.START_HOT) {
        console.log('Starting Main Process... ');
        spawn('npm'['run'.'start-main-dev'] and {// Before running the server, run the 'start-main-dev' directive in package.json, as configured below.
          shell: true.env: process.env,
          stdio: 'inherit',
        })
          .on('close', code => process.exit(code))
          .on('error', spawnError => console.error(spawnError)); ,}}}});Copy the code

Finally posted the rendering process production environment webpack: new config files/webpack/webpack config. The renderer. Prod. Babel. Js

const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const merge = require('webpack-merge');
const TerserPlugin = require('terser-webpack-plugin');
const baseConfig = require('./webpack.config.base');

module.exports = merge.smart(baseConfig, {
  devtool: 'source-map'.mode: 'production'.target: 'electron-renderer'.entry: {
    renderer: require.resolve('.. /.. /src/render-process/index.tsx'),},output: {
    path: path.join(__dirname, '.. '.'.. /dist'),
    publicPath: './dist/'.filename: '[name].prod.js',},optimization: {
    minimizer: process.env.E2E_BUILD
      ? []
      : [
        new TerserPlugin({
          parallel: true.sourceMap: true.cache: true,}).new OptimizeCSSAssetsPlugin({
          cssProcessorOptions: {
            map: {
              inline: false.annotation: true},},}),],},plugins: [
    new webpack.EnvironmentPlugin({
      NODE_ENV: 'production',}).new MiniCssExtractPlugin({
      filename: 'style.css',}).new BundleAnalyzerPlugin({
      analyzerMode: process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled'.openAnalyzer: process.env.OPEN_ANALYZER === 'true',})]});Copy the code
  1. Remember we used it when we ran that demo againts-node./src/main-process/main.tsRun lets us use the Node environment ts directly. But not yetts-electronLet’s run TS directly with electron. So we need to handle our run entry with Babel. We just need toconfigCreate a new directory:babel-entry-config.js
module.exports = {
  extensions: ['.js'.'.ts'.'.tsx'].presets: [['@babel/preset-env',
      {
        targets: { electron: require('electron/package.json').version },
        useBuiltIns: 'usage'.modules: 'commonjs'],},'@babel/preset-typescript',].plugins: [['@babel/plugin-proposal-decorators', { legacy: true}]],};Copy the code

Then create entry.dev.js under SRC:

require('@babel/register') (require('.. /config/babel-entry-config'));
require('./main-process/main');
Copy the code

Finally, let’s change the package.json command:

."start-main-dev": "cross-env HOT=1 NODE_ENV=development electron -r @babel/register ./src/entry.dev.js"."dev": "cross-env START_HOT=1 webpack-dev-server --config ./config/webpack/webpack.config.renderer.dev.babel.js".Copy the code
  1. We’re just one more step away from running inrender-processLet’s go ahead and create a new oneindex.tsx. aboutrender-processTo see what the new TSX means, see the main process and render process article above:Electron- Main process, render process
console.log('Hello Autumn Rain');
Copy the code

Yarn Dev: yarn Dev: yarn Dev: yarn Dev: yarn Dev: yarn Dev: yarn Dev: yarn Dev

yarn add cross-env webpack-dev-server webpack-merge mini-css-extract-plugin @babel/register @babel/plugin-proposal-decorators @babel/preset-typescript -D
Copy the code

Finally, you can see the window with the HTML loaded by the window, and the console.log output of the HTML loaded JS: ‘Hello Qiu Ze Yu’.

The following figure shows the operation process after YARN Dev:

This article demo: github.com/spcBackToLi…

The react+ MOBx integration will be covered in the next post