티스토리 뷰

vue, vuetify로 웹페이지를 개발하다가 점점 시간이 지나다 보니 공통화해도 괜찮겠다 싶은 부분을 모아 유틸을 만들게 되었습니다. 

이 유틸을 하나의 소스에서 사용할 때는 문제가 없었는데 3개정도 넘어가기 시작하면서 업데이트하기가 힘들어 졌고 npm package로 배포해서 사용하면 좋겠다는 생각을 하게 되었죠. 

 

일단은 아래 블로그를 참고하여 npm에 첫번째 배포를 성공했습니다.

velog.io/@rnfh1111/1

[Vue] Component NPM에 배포 삽질기

NPM에 첫 배포를 시도해 보았습니다. 완벽하지는 않지만 한글로 된 자료가 많이 없기에 작성해 봅니다. 목표 vue에서 사용 가능한 widget 형식의 modal을 만들어 배포해 보려고 합니다. 환경 작업환경

velog.io

음 근데 뭔가 이상한게 제가 작성한 소스 코드은 그렇게 많지 않은데 배포된 소스는 몇십메가가 넘어가고 npm install 로 설치해서 실행해 보니 제대로 돌아가질 않습니다.

 

여기저기 검색을 하다보니 library 배포는 webpack 배포와는 방법이 좀 달라 우선 vue 공식문서에서 설명된 대로 따라 해보았습니다. rollup 을 처음 접하게 되었습니다.

kr.vuejs.org/v2/cookbook/packaging-sfc-for-npm.html

Packaging Vue Components for npm — Vue.js

Vue.js - 프로그레시브 자바스크립트 프레임워크

kr.vuejs.org

제가 배포하는 소스 구조는 아래와 같습니다. 

 

 

 

* index.js

install 후 component 형태로 사용할 예정이므로 아래와 같이 사용할 vue 컴포넌트를 import / export 해 주었습니다. 

import component from './components/MyComponent.vue'

export {
  component
}

function install(Vue) {
  Vue.component('패키지명', component)
}

export default install

// Install by default if included from script tag
if (typeof window !== 'undefined' && window.Vue) {
  window.Vue.use(install)
}

pakage.json

공식문서에 설명된데로 적당히 작성해 보았습니다. 

dependencies에 있던 필수 패키지는 향후 패키지 설치시 참조로 사용하기 위해 peerDependencies 로 옮겼습니다. 

제가 만든 패키지가 정상작동 하기 위해서는 vue, vuetify, lodash 세가지가 필수로 필요합니다.

{
  "name": "패키지명",
  "version": "1.0.0",
  "description": "Use vuetify 2.x component from your script",
  "author": "dongqueue <dongqueue@gmail.com>",
  "scripts": {
    "build": "npm run build:umd & npm run build:es & npm run build:unpkg",
    "build:umd": "rollup --config ./rollup.config.js --format umd --file dist/패키지명.umd.js",
    "build:es": "rollup --config ./rollup.config.js --format es --file dist/패키지명.esm.js",
    "build:unpkg": "rollup --config ./rollup.config.js --format iife --file dist/패키지명.min.js"
  },
  "main": "dist/패키지명.umd.js",
  "module": "dist/패키지명.esm.js",
  "unpkg": "dist/패키지명.min.js",
  "keywords": [
    "vuetify",
    "script"
  ],
  "license": "MIT",
  "dependencies": {},
  "devDependencies": {
    "@rollup/plugin-alias": "^3.1.2",
    "@vue/cli-plugin-babel": "^4.5.11",
    "@vue/cli-plugin-eslint": "^4.5.11",
    "@vue/cli-service": "^4.5.11",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.2.2",
    "raw-loader": "^4.0.2",
    "rollup": "^2.40.0",
    "rollup-plugin-buble": "^0.19.8",
    "rollup-plugin-commonjs": "^10.1.0",
    "rollup-plugin-multi-entry": "^2.1.0",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-vue": "^5.1.9",
    "sass": "^1.32.8",
    "sass-loader": "^8.0.0",
    "vue": "^2.6.11",
    "vue-cli-plugin-vuetify": "^2.1.0",
    "vue-template-compiler": "^2.6.11",
    "vuetify": "^2.4.5",
    "vuetify-loader": "^1.7.2"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "parserOptions": {
      "parser": "babel-eslint"
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ],
  "peerDependencies": {
    "lodash": "*",
    "vue": "*",
    "vuetify": "*"
  },
  "eslintIgnore": [
    "dist/"
  ]
}

rollup.config.js 를 작성해 봅니다. (아래 파일에 나열된 모듈을 -D 옵션으로 설치합니다.)

import commonjs from 'rollup-plugin-commonjs'; // Convert CommonJS modules to ES6
import vue from 'rollup-plugin-vue'; // Handle .vue SFC files
import buble from 'rollup-plugin-buble'; // Transpile/polyfill with reasonable browser support
import resolve from 'rollup-plugin-node-resolve' // resolve node import or require
import multi from 'rollup-plugin-multi-entry' // build files in multi path
import alias from '@rollup/plugin-alias' // replace @ path to real path

export default {
  input: ['src/index.js', 'src/logic/*.js', 'src/components/*.vue', 'src/components/core/*.vue'], // Path relative to package.json
  output: {
    name: '패키지명',
    exports: 'named',
    inlineDynamicImports: true
  },
  plugins: [
    commonjs(),
    vue({
      css: true, // Dynamically inject css as a <style> tag
      template: {
        isProduction: true
      },
      compileTemplate: true, // Explicitly convert template to render function
    }),
    buble({ objectAssign: 'Object.assign' }), // Transpile to ES5
    multi(),,
    alias({ entries: [{ find: /^@\/(.+)/, replacement: 'src/$1' }]}),
    resolve()
  ],
};

공식문서에는 'rollup-plugin-node-resolve', 'rolllup-plugin-multi-entry', '@rollup/plugin-alias' 가 없습니다.

제 경우 MyComponent.vue 를 export 해서 사용하는데 MyComponent는 다른 폴더에 있는 파일을 require / import 해서 사용하게 되어서 다른 폴더를 포함해서 빌드해야 합니다.

 

'rollup-plugin-multi-entry' 가 없는 경우 index.js 에서 require/import하는 파일만 빌드하기 때문에 이 모듈을 설치하고 input에 원하는 경로를 array형태로 추가하였습니다.

import multi from 'rollup-plugin-multi-entry'
...

input: ['src/index.js', 'src/logic/*.js', 'src/components/*.vue', 'src/components/core/*.vue'],
plugins: [
  multi()
]

'rollup-plugin-node-resolve' 는 require/import 구문을 해석해서 해당 파일을 빌드에 포함시킵니다.

import resolve from 'rollup-plugin-node-resolve'

plugins: [
  resolve()
]

'@rollup/plugin-alias' 는 require/import 구분의 @ 경로를 해석할 수 있도록 도와줍니다.

import alias from '@rollup/plugin-alias'
...
plugins: [
  alias({ entries: [{ find: /^@\/(.+)/, replacement: 'src/$1' }]}),
]

이제 bulid 하게 되면 처음 의도했던대로 tree shaking이 되어 빌드가 진행됩니다.

 

 

파일 사이즈도 원하던 대로 잘 나왔네요.

 

 

이제 readme.md 를 작성하고 publish 하여 npm에 등록하면 되겠습니다. :)

댓글