Next.js 에서 빌드타임 줄이는 이야기(Babel ⇢ SWC)

devPomme·2022년 10월 12일
3
post-custom-banner
번들러BabelSWC
1회차73.64s48.98s
2회차70.85s42.12s
3회차74.43s40.69s
4회차63.38s44.66s
5회차70.64s42.91s
6회차62.3s42.15s
7회차66.98s45.56s
8회차65.63s41.97s
9회차62.38s40.51s
10회차76.39s38.56s
평균67.662s42.811s

빌드는 node_modules, dist, .next 디렉토리를 삭제한 후 yarn install && next build && tsc --project tsconfig.server.json 으로 실행하였다.

변경 전


info  - Linting and checking validity of types .warn  - The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config
info  - Linting and checking validity of types  

/*****현재 커스텀 바벨 설정(.babelrc)때문에 SWC가 비활성화 처리되었다고 알려준다.*****/
info  - Disabled SWC as replacement for Babel because of custom Babel configuration ".babelrc" 


https://nextjs.org/docs/messages/swc-disabled

(node:14789) [DEP_WEBPACK_MODULE_UPDATE_HASH] DeprecationWarning: Module.updateHash: Use new ChunkGraph API
(Use `node --trace-deprecation ...` to show where the warning was created)
info  - Creating an optimized production build ...<w> [webpack.cache.PackFileCacheStrategy] Skipped not serializable cache item '... /node_modules/@toast-ui/editor/dist/toastui-editor.css': No serializer registered for Warning
<w> while serializing webpack/lib/cache/PackFileCacheStrategy.PackContentItems -> webpack/lib/NormalModule -> Array { 1 items } -> webpack/lib/ModuleWarning -> Warning
info  - Creating an optimized production build  
warn  - Compiled with warnings

./node_modules/@toast-ui/editor/dist/toastui-editor.css.webpack[javascript/auto]!=!./node_modules/next/dist/build/webpack/loaders/css-loader/src/index.js??ruleSet[1].rules[2].oneOf[7].use[1]!./node_modules/next/dist/build/webpack/loaders/postcss-loader/src/index.js??ruleSet[1].rules[2].oneOf[7].use[2]!./node_modules/@toast-ui/editor/dist/toastui-editor.css
Warning

(59:1) postcss-import: @charset must precede all other statements

Import trace for requested module:
./node_modules/@toast-ui/editor/dist/toastui-editor.css
./src/components/Community/ToastEditor.tsx
./src/pages/community/write.tsx

info  - Collecting page data ..redux-persist failed to create sync storage. falling back to noop storage.
redux-persist failed to create sync storage. falling back to noop storage.
Warning: You have opted-out of Automatic Static Optimization due to `getInitialProps` in `pages/_app`. This does not opt-out pages with `getStaticProps`
Read more: https://nextjs.org/docs/messages/opt-out-auto-static-optimization

info  - Collecting page data  
/*생략*/
λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)

✨  Done in 76.39s.

변경 후


info  - Linting and checking validity of types .warn  - The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config
info  - Linting and checking validity of types  
(node:15372) [DEP_WEBPACK_MODULE_UPDATE_HASH] DeprecationWarning: Module.updateHash: Use new ChunkGraph API
(Use `node --trace-deprecation ...` to show where the warning was created)
info  - Creating an optimized production build  
info  - Compiled successfully
info  - Collecting page data ..redux-persist failed to create sync storage. falling back to noop storage.
redux-persist failed to create sync storage. falling back to noop storage.

Warning: You have opted-out of Automatic Static Optimization due to `getInitialProps` in `pages/_app`. This does not opt-out pages with `getStaticProps`
Read more: https://nextjs.org/docs/messages/opt-out-auto-static-optimization

info  - Collecting page data  
/*생략*/
λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)

✨  Done in 38.56s.

사용하지 않는 webpack 모듈 삭제 + .babelrc 삭제 + SWC 옵션 적용

/** @type {import('next').NextConfig} */
const path = require('path');
const prod = process.env.NODE_ENV === 'production';

const withImages = require('next-images');
const { webpack } = require('webpack');

module.exports = {
  reactStrickMode: false,
  trailingSlash: true,
  productionBrowserSourceMaps: false,
  // 
  webpack: (config) => {
    return {
      ...config,
      infrastructureLogging: { debug: /PackFileCache/ },
      devtool: prod ? 'hidden-source-map' : 'inline-source-map',
    };
  },
   swcMinify: true, // babel 대신 swc를 사용할 것이므로 옵션활성화
  /** 스타일드 컴포넌트를 적용해야한다. babel-plugin-styled-components를 설치하고 ssr 옵션을 true 로 설정해줄 필요 없이 이렇게만 작성하면 끝이다. (displayname : true, ssr: true)로 설정됨  **/
  compiler: {
    styledComponents: true,
  }, 
   
  experimental: {
    esmExternals: true,
    scrollRestoration: true,
    // lodash 모듈도 사용하고자 하는 개별 함수들만 임포트해서 Tree Shaking 할 수 있게 적용하였다.
    modularizeImports: {
      lodash: { transform: 'lodash/{{member}}' },
    },
  },
  
  
  /** 
   파일이 변경될 때마다 이를 감지하여 다시 컴파일하는 옵션도 굳이 필요할 것같지 않아 주석처리를 했다.
   
  webpackDevMiddleware: (config) => {
    config.watchOptions = {
      poll: 1000,
      aggregateTimeout: 300,
    };
    return config;
  }, **/

  experimental: {
    scrollRestoration: true,
  },
  resolve: {
    alias: {
      '@pages': path.resolve(__dirname, 'src/pages'),
      '@components': path.resolve(__dirname, 'src/components'),
      '@layouts': path.resolve(__dirname, 'src/layouts'),
      '@store': path.resolve(__dirname, 'src/store'),
    },
  },
  reactStrictMode: true,


  rewrites: async () => {
    return [
      {
        source: '/public',
        destination: '/public/servicecheck.html',
      },
    ];
  },
};




// 아래 부분은 모두 주석처리를 해도 빌드 및 배포에 문제가 없어 삭제처리를 했다.
/** module.exports = withImages({
  webpack(config, options) {
    config.module.rules.push({
      test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2|ogg|mp3|wav|mpe?g)$/i,
      use: [
        {
          loader: 'url-loader',
          options: {
            name: '[name]-[hash].[ext]',
          },
        },
      ],
    });
    return config;
  },
});

module.exports = {
  webpack(config) {
    config.module.rules.push({
      test: /\.svg$/i,
      issuer: { and: [/\.(js|ts|md)x?$/] },
      use: [
        {
          loader: '@svgr/webpack',
          options: {
            prettier: false,
            svgo: true,
            svgoConfig: { plugins: [{ removeViewBox: false }] },
            titleProp: true,
          },
        },
      ],
    });
    return config;
  },
};
const withReactSvg = require('next-react-svg');

module.exports = withReactSvg({
  include: path.resolve(__dirname, '/public/svg'),
  webpack(config, options) {
    config.module.rules.push({
      test: /\.svg$/,
      use: ['@svgr/webpack'],
    });

    return config;
  },
}); **/


사용하지 않는 postCSS 모듈도 삭제

module.exports = {
  plugins: {
    // 'postcss-import': {},
    autoprefixer: {},
    tailwindcss: {},
    'postcss-flexbugs-fixes': {},
    /** 'postcss-preset-env': {
      autoprefixer: {
        flexbox: 'no-2009',
      },
      stage: 3,
      features: {
        'custom-properties': false,
      },
    }, **/
  },
};

느낀 점

뭔가 더 드라마틱하게 빌드 타임이 축소되진 않아서 좀 아쉬웠다. 소스 코드에서 빌드 타임을 줄일 수 있는 방법은 없는 지, 더 고민해보고 리팩토링을 진행해봐야겠다는 생각이 들었다.

참고 자료
[Next.js]Modularize-Imports
[Next.js]Why SWC?

profile
헌신하고 확장하는 삶
post-custom-banner

0개의 댓글