View

[Vue] vue cli의 pages 옵션

mmong mong 2021. 5. 11. 18:28

배경

회사에서 구현해야 하는 앱은 일반 사용자용 화면과 관리자용 화면이 필요하다. 페이지는몇 개 없지만 업무 상 이런 류의 앱을 만들어야 할 상황이 자주 온다.

이제까지는 한개의 레포지토리에서 vue cli를 사용하여 user, admin 프로젝트를 각각 만들어 사용했는데 user와 admin의 룩앤필이 같아서 중복 코드가 매우 많았다. 

레포지토리를 user, admin으로 분리하기엔 페이지가 너무 적어서 비효율적이라 한개의 레포지토리는 유지하되 중복코드만 분리하는 방법을 고민하던 중 vue cli의 pages 옵션을 활용해보기로 했다!

Pages

  • Type:  Object
  • Default: undefined
  • Build the app in multi-page mode. Each "page" should have a corresponding JavaScript entry file. The value should be an object where the key is the name of the entry, and the value is either:
    • An object that specifies its entry, template, filename, title and chunks (all optional except entry). Any other properties added beside those will also be passed directly to html-webpack-plugin, allowing user to customize said plugin;
    • Or a string specifying its entry.

객체로 옵션을 설정할 수 있고, entry만 설정할거면 string으로 세팅이 가능하다.

html-webpack-plugin의 옵션 또한 설정할 수 있는 듯 하다.

 

module.exports = {
  pages: {
    index: { // (1)
      entry: 'src/index/main.js', // (2)
      template: 'public/index.html', // (3)
      filename: 'index.html', // (4)
      title: 'Index Page', // (5)
      chunks: ['chunk-vendors', 'chunk-common', 'index'] // (6)
    },
    subpage: 'src/subpage/main.js' // 이 부분은 아직 잘 모르겠다..
  }
}

index

설정할 page의 name(여기서는 index)이다.
빌드한 뒤 브라우저에서 page name으로 접근한다.

entry

설정한 page의 entry 파일 위치다.

 

template

vue cli로 프로젝트를 생성하면 public/index.html이 기본 템플릿 파일이고, 여기서 favicon 등을 설정할 수 있다.
template 옵션을 사용하면 page 별로 다른 템플릿 파일을 사용할 수 있다.

(html-webpack-plugin 옵션을 사용할 수 있기 때문에 chainWebpack 옵션으로 설정해도 된다. https://cli.vuejs.org/guide/webpack.html#modifying-options-of-a-plugin)

 

filename

빌드 결과물로 떨어질 html 파일의 이름이다. (e.g. dist/index.html)

 

title

page의 title을 설정한다.
이 옵션을 사용한 경우 템플릿 파일에 아래 코드를 추가해야 타이틀이 정상적으로 표시된다. 

<title><%= htmlWebpackPlugin.options.title %></title>

chunks

설정하면 지정한 chunk 파일만 load 한다. 

 


예제 #1 template 옵션

vue.config.js

// admin, user 페이지 설정
module.exports = {
  pages: {
    admin: {
      entry: 'src/admin/main.js',
      template: 'public/admin.html',
      filename: 'admin.html',
      title: 'Admin Page'
    },
    user: {
      entry: 'src/user/main.js',
      template: 'public/user.html',
      filename: 'user.html',
      title: 'User Page'
    }
  }
}

public/admin.html

favicon으로 starfish-blue 설정

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" type="image/png" sizes="32x32" href="<%= BASE_URL %>icons8-starfish-blue.png" />
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    Admin Template
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

public/user.html

favicon으로 starfish-yellow 설정

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" type="image/png" sizes="32x32" href="<%= BASE_URL %>icons8-starfish-yellow.png" />
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    User Template
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

 

실행 결과

  • 설정한 page 이름(admin, user)으로 브라우저에서 접근할 수 있다.
  • 각각 설정한 template 파일이 표시된다. (title 옵션과 template 파일의 파비콘이 다르다.)

user page와 admin page에 접근했을 때의 각 화면

 

 

 

예제 #2 chunks 옵션

vue.config.js

// admin, user 페이지 설정
module.exports = {
  pages: {
    admin: {
      entry: 'src/admin/main.js',
      template: 'public/admin.html',
      filename: 'admin.html',
      title: 'Admin Page',
      chunks: ['admin', 'chunk-vendors']
    },
    user: {
      entry: 'src/user/main.js',
      template: 'public/user.html',
      filename: 'user.html',
      title: 'User Page',
      chunks: ['user', 'chunk-vendors', 'chunk-lodash']
    }
  },
  configureWebpack: {
    optimization: {
      splitChunks: {
        cacheGroups: {
          vendors: {
            test: /[\\/]node_modules[\\/]/,
            name: 'chunk-vendors',
            enforce: true,
            chunks: 'all'
          },
          lodash: {
            test: /[\\/]node_modules[\\/](lodash)[\\/]/,
            name: 'chunk-lodash',
            enforce: true,
            chunks: 'all'
          }
        }
      }
    }
  }
}

 

 

  • configureWebpack의 optimization 옵션
    • 설정한 경우 번들링 결과
      • admin.js, user.js, chunk-vendors.js, chunk-lodash.js 
    • 설정 안 한 경우 번들링 결과
      • admin.js, user.js, chunk-vendors.js
  • pages의 chunk 옵션
    • 이 옵션을 설정하면 array에 포함된 js 파일만 load 한다.

실행 예시

  • configureWebpack의 optimization 옵션을 설정
    • admin.js, user.js, chunk-vendors.js, chunk-lodash.js가 번들링된다.
  • pages.admin.chunks = ["admin.js", "lodash.js"]로 설정한 경우
    • 위 4개(admin.js, user.js, vendors.js, lodash.js) 중 admin.jschunk-lodash.js만 load 됨

위와 같이 4개의 파일이 번들링됨 (webpack-bundle-analyzer를 사용)
admin 페이지에서 불러오는 파일은 chunks 옵션에 설정한 파일들

 

 


결론

아직 팀원들의 리뷰를 못 받아 업무에 적용하지는 못했지만 옵션만 봤을 때엔 필요한 요건에 잘 부합하는 것으로 보인다.

admin과 user가 각각 가져가야 하는 파일(router, 페이지 컴포넌트 등)은 디렉토리를 분리하고,

common 디렉토리를 추가해서 공통으로 사용하는 파일(공통 컴포넌트, 공통 헬퍼 모듈 등)만 관리할 수 있을 것 같다.

특히 마지막 예제인 chunks 옵션을 사용해서 admin 또는 user에서만 사용하는 패키지를 따로 load 하는 건 최적화에 유용할 것 같다.

 

단, router의 history 모드를 사용하는 경우 이슈가 있는 것 같다. 이 부분은 링크로 대신한다.

https://soobakba.tistory.com/32

 

그리고 찾다보니 pages 옵션이 MPA(Multi-Page-Application)에 활용하는 옵션같은데.. SPA는 많이 들어봤어도 MPA는 들어보지 못해서 생소했다. 찾아보면서 MPA에 대해서도 좀 알게 된거 같아 좋았다.

 

관련 링크

 

 

Share Link
reply