티스토리 뷰

Electron앱을 패키징했다. 근데 앱 용량이 너무 크다.

 

무려 662MB

 

원래 일렉트론으로 만든 앱 용량이 기본적으로 크다곤 하지만, 대표적인 Electron앱인 디스코드는 392MB, vscode는 549MB다. 그래서 어떻게 줄이는지 찾아보다가, 배포할 때 제외할 리소스를 극한으로 설정하거나 필요없는 라이브러리는 삭제시키면 된다는 해결방법이 대부분이었다.  하지만 필요없는 라이브러리 삭제같은 해결방법은 기존부터 해왔기에, 용량을 다이나믹하게 줄이려면 다른 방법이 필요했다. 

 

그러다가 electron-react-boilerplate를 찾았고, 혹시라도 보일러플레이트 앱을 패키징하면 용량이 작게 나올지도 모른다는 생각에 설명에 적힌대로 빌드를 해봤다. 

 

git clone 후

git clone https://github.com/electron-react-boilerplate/electron-react-boilerplate.git

 

라이브러리를 설치한다.

npm i

 

설치가 끝났다면 패키징 명령어를 입력한다.

npm run package

 

역시나, 223MB밖에 되지 않았다. 

 

내 앱과 3배차이

어떻게 용량을 줄였는지 코드를 살펴보던 중, 빌드를 webpack으로 번들링된 파일로 한다는걸 알게 되었다. 백엔드라서 webpack을 한번도 써보진 않았기 때문에, 번들링만 해주었을 뿐인데 저렇게 다이나믹하게 용량이 줄어드나? 생각했다. webpack으로 번들링을 하면 여러 js파일이 하나의 js파일로 묶이고 압축하기, 난독화 등 으로 불필요한 공백과 개행을 줄여 코드를 압축시킬 수 있다고 한다. 

 

그럼 webpack을 사용해서 Electron앱 용량을 줄여보도록 하자. 먼저 webpack과 webpack-cli, webpack-merge를 설치해준다. main process와 render process를 따로 번들링하기 때문에 공통로직은 webpack-merge로 분리하는게 편하다. 

npm i -D webpack webpack-cli webpack-merge

 

먼저 webpack.config.base.ts 파일을 생성하고 공통으로 작업하는 로직을 작성해보자.

import webpack from 'webpack';
import TsconfigPathsPlugins from 'tsconfig-paths-webpack-plugin';

const configuration: webpack.Configuration = {
  module: {
    rules: [
      {
        test: /\.[jt]sx?$/,
        exclude: /node_modules/,
        use: {
          loader: 'ts-loader',
          options: {
            //번들링하기 전 타입체크 생략
            transpileOnly: true,
            compilerOptions: {
              module: 'esnext',
            },
          },
        },
      },
    ],
  },

  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
    modules: [webpackPaths.srcPath, 'node_modules'],
    plugins: [new TsconfigPathsPlugins()],
  },
};

export default configuration;

 

TypeScript로 Electron앱을 구현하고 있기 때문에 TypeScript를 읽을 수 있는 loader를 사용한다.

(webpack은 JavaScript만 읽는다.)

 

그리고 webpack.config.main.prod.ts 파일을 생성하고, main-process 안에 있는 종속적인 파일들을 번들링해보자. 

import webpack from 'webpack';
import path from 'path';
import webpackPaths from './webpack.paths';
import TerserPlugin from 'terser-webpack-plugin';
import baseConfig from './webpack.config.base';
import { merge } from 'webpack-merge';
import Dotenv from 'dotenv-webpack';

const configuration: webpack.Configuration = {
  externals: {
    //ws 외부 종속성 번들링 제외
    bufferutil: 'bufferutil',
    'utf-8-validate': 'utf-8-validate',
  },

  devtool: 'source-map',

  mode: 'production',

  target: 'electron-main',

  entry: path.join(webpackPaths.srcMainPath, 'main.ts'),

  output: {
    path: webpackPaths.disMainPath,
    filename: 'main.js',
    library: {
      type: 'umd',
    },
  },

  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true,
      }),
    ],
  },

  plugins: [
    new Dotenv(),
  ],

  node: {
    __dirname: false,
    __filename: false,
  },
};

export default merge(baseConfig, configuration);

 

webpackPaths는 경로만 따로 뺀거니 원하는 경로를 지정해주면 된다. 다른건 기본적인 것들이라 넘어가고, (mode를 production으로 하면 webpack 내부에서 최적화를 진행한다.) 밑에 있는 코드가 파일을 압축(최적화)시키는 코드다. parallel을 true로 하면 파일 압축 작업을 병렬로 진행해 압축속도를 높일 수 있다. 

 

optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true,
      }),
    ],
  },

 

마지막으로 webpack.config.renderer.prod.ts 파일을 생성하고 renderer코드를 번들링해보자. 이것 역시 파일을 압축하는 코드가 포함되어있다. png와 svg 이미지를 사용하기 때문에, 각각 맞는 loader로 번들링해주었다.

import webpack from 'webpack';
import path from 'path';
import webpackPaths from './webpack.paths';
import TerserPlugin from 'terser-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import baseConfig from './webpack.config.base';
import { merge } from 'webpack-merge';
import Dotenv from 'dotenv-webpack';

const configuration: webpack.Configuration = {
  devtool: 'source-map',

  mode: 'production',

  target: ['web', 'electron-renderer'],

  entry: [path.join(webpackPaths.srcPath, 'index.tsx')],

  output: {
    path: webpackPaths.distRendererPath,
    publicPath: './',
    filename: 'renderer.js',
    library: {
      type: 'umd',
    },
  },

  module: {
    rules: [
      {
        test: /\.png$/,
        type: 'asset/resource',
      },
      {
        test: /\.svg$/,
        use: [
          {
            loader: '@svgr/webpack',
            options: {
              prettier: false,
              svgo: false,
              svgoConfig: {
                plugins: [{ removeViewBox: false }],
              },
              titleProp: true,
              ref: true,
            },
          },
          'file-loader',
        ],
      },
    ],
  },

  optimization: {
    minimize: true,
    minimizer: [new TerserPlugin()],
  },

  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: path.join(webpackPaths.publicPath, 'index.html'),

      minify: {
        collapseWhitespace: true,
        removeAttributeQuotes: true,
        removeComments: true,
      },
      isBrowser: false,
      isDevelopment: false,
    }),

    new Dotenv(),
  ],
};

export default merge(baseConfig, configuration);

 

이제 빌드할 때 아래와 같이 webpack 번들링 후 번들링된 파일로 패키징하면 된다. 

"scripts": {
    "build": "concurrently \"npm run build:main\" \"npm run build:renderer\"",
    "build:main": "webpack --config ./.erb/configs/webpack.config.main.prod.ts",
    "build:renderer": "webpack --config ./.erb/configs/webpack.config.renderer.prod.ts",
    "package": "npm run build && electron-builder build --publish never",
  },

나는 이 사진처럼 위치해 놓았다. webpack 설정파일 경로를 잘 적어주자.

 

완료된 앱 용량을 확인하면?

 

 

약 3배가 줄어든것을 볼 수 있다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday