Home:ALL Converter>Trying to build vue component library using rollup and vueJs 3

Trying to build vue component library using rollup and vueJs 3

Ask Time:2020-10-20T13:06:12         Author:shubh

Json Formatter

I am trying to create a vue component library using rollup and vuejs. It worked with vue2 but was unable to parse css with vue3. I have upgraded the dependency in package.json

package.json

{
  "name": "vue2tslibrary",
  "version": "0.1.59",
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "build:js": "rimraf dist && rollup -c && rollup -c --environment MINIFY"
  },
  "sideEffects": [
    "*.css",
    "*.scss"
  ],
  "files": [
    "dist",
    "src"
  ],
  "main": "dist/cjs/index.js",
  "module": "dist/esm/index.js",
  "unpkg": "dist/vueslib.min.js",
  "dependencies": {
    "@mathieustan/vue-datepicker": "^0.2.8",
    "core-js": "^3.6.5",
    "date-fns": "^2.16.1",
    "vue": "^3.0.1",
    "vue-router": "^4.0.0-beta.13",
    "vue-slider-component": "^4.0.0-beta.2",
    "vue-template-compiler": "^2.6.12",
    "vuex": "^4.0.0-beta.4"
  },
  "devDependencies": {
    "@babel/plugin-proposal-optional-chaining": "^7.12.1",
    "@rollup/plugin-alias": "2.2.0",
    "@rollup/plugin-babel": "^5.2.1",
    "@rollup/plugin-commonjs": "^15.1.0",
    "@rollup/plugin-image": "^2.0.5",
    "@rollup/plugin-node-resolve": "^9.0.0",
    "@rollup/plugin-url": "^5.0.1",
    "@typescript-eslint/eslint-plugin": "^2.33.0",
    "@typescript-eslint/parser": "^2.33.0",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-plugin-typescript": "~4.5.0",
    "@vue/cli-plugin-vuex": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.1",
    "@vue/eslint-config-standard": "^5.1.2",
    "@vue/eslint-config-typescript": "^5.0.2",
    "autoprefixer": "^9.8.6",
    "cssnano": "^4.1.10",
    "eslint": "^6.7.2",
    "eslint-plugin-import": "^2.20.2",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-promise": "^4.2.1",
    "eslint-plugin-standard": "^4.0.0",
    "eslint-plugin-vue": "^6.2.2",
    "node-sass": "^4.14.1",
    "postcss": "^8.1.1",
    "postcss-calc": "^7.0.3",
    "postcss-color-function": "^4.1.0",
    "postcss-cssnext": "^3.1.0",
    "postcss-discard-comments": "^4.0.2",
    "postcss-discard-empty": "^4.0.1",
    "postcss-discard-unused": "^4.0.1",
    "postcss-each": "^0.10.0",
    "postcss-extend-rule": "^3.0.0",
    "postcss-import": "^12.0.1",
    "postcss-mixins": "^6.2.3",
    "postcss-nested": "^4.2.1",
    "postcss-rem": "^1.1.5",
    "postcss-simple-vars": "^5.0.2",
    "postcss-sort-media-queries": "^1.7.26",
    "postcss-url": "^8.0.0",
    "rollup": "1.17.0",
    "rollup-plugin-analyzer": "^3.3.0",
    "rollup-plugin-babel": "^4.4.0",
    "rollup-plugin-commonjs": "^10.1.0",
    "rollup-plugin-css-only": "^2.1.0",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-postcss": "^3.1.8",
    "rollup-plugin-terser": "^7.0.2",
    "rollup-plugin-typescript": "^1.0.1",
    "rollup-plugin-typescript2": "^0.28.0",
    "rollup-plugin-uglify": "^6.0.4",
    "rollup-plugin-vue": "^6.0.0-beta.8",
    "sass-loader": "^10.0.3",
    "style-resources-loader": "1.3.3",
    "typescript": "~3.9.3"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "@vue/standard",
      "@vue/typescript/recommended"
    ],
    "parserOptions": {
      "ecmaVersion": 2020
    },
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

rollup.config.js

import vue from 'rollup-plugin-vue'
import node from '@rollup/plugin-node-resolve'
import cjs from '@rollup/plugin-commonjs'
import babel from '@rollup/plugin-babel'
import postcss from 'rollup-plugin-postcss'
import { terser } from 'rollup-plugin-terser'
import css from 'rollup-plugin-css-only'
import postcssImport from 'postcss-import'
import autoprefixer from 'autoprefixer'
import simplevars from 'postcss-simple-vars'
import nested from 'postcss-nested'
import postcssEach from 'postcss-each'
import postcssMixin from 'postcss-mixins'
import postcssColor from 'postcss-color-function'
import postcssCalc from 'postcss-calc'
import postcssextend from 'postcss-extend-rule'
import postcssDiscardComment from 'postcss-discard-comments'
import postcssDiscardEmpty from 'postcss-discard-empty'
import postcssUrl from 'postcss-url'
import postcssRem from 'postcss-rem'
import sortMedia from 'postcss-sort-media-queries'
import cssnano from 'cssnano'
import url from '@rollup/plugin-url'
import typescript from 'rollup-plugin-typescript2'
import analyze from 'rollup-plugin-analyzer'

import fs from 'fs'
import path from 'path'

const babelConfig = {
  exclude: 'node_modules/**',
  babelHelpers: true,
  babelrc: false,
  presets: [['@babel/preset-env', { modules: false }]]
}

const baseFolder = './src/'
const componentsFolder = 'components/'

const components = fs
  .readdirSync(baseFolder + componentsFolder)
  .filter((f) =>
    fs.statSync(path.join(baseFolder + componentsFolder, f)).isDirectory()
  )

const entries = {
  index: './src/index.ts',
  ...components.reduce((obj, name) => {
    obj[name] = (baseFolder + componentsFolder + name)
    return obj
  }, {})
}

const capitalize = (s) => {
  if (typeof s !== 'string') return ''
  return s.charAt(0).toUpperCase() + s.slice(1)
}

const vuePluginConfig = {
  defaultLang: {
    style: 'postcss',
    script: 'ts'
  },
  transformAssetUrls: {
    includeAbsolute: true
  },
  preProcessStyles: true,
  compileTemplate: false,
  template: {
    isProduction: true,
    compilerOptions: {
      whitespace: 'condense'
    }
  },
  style: {
    postcssPlugins: [
      autoprefixer,
      postcssImport({
        resolve (id, basedir) {
          // resolve alias @css, @import '@css/style.css'
          // because @css/ has 5 chars
          if (id.startsWith('@css')) {
            // basedir will resolve to /src/components
            return path.resolve('src/assets/styles/css', id.slice(5))
          }

          // resolve node_modules, @import '~normalize.css/normalize.css'
          // similar to how css-loader's handling of node_modules
          // if (id.startsWith('~')) {
          //   return path.resolve(basedir, '../node_modules', id);
          // }

          // resolve relative path, @import './components/style.css'
          return path.resolve(basedir, id)
        }
      }),
      postcssEach,
      postcssMixin,
      simplevars,
      postcssColor,
      postcssCalc,
      nested,
      postcssextend,
      postcssDiscardComment,
      postcssDiscardEmpty,
      postcssUrl({ url: 'inline' }),
      postcssRem({
        baseline: 16, // Default to 16
        // convert: 'px', // Default to rem
        fallback: true, // Default to false
        precision: 6 // Default to 5
      }),
      sortMedia({
        sort: 'mobile-first'
      }),
      autoprefixer({
        overrideBrowserslist: '> 1%, IE 6, Explorer >= 10, Safari >= 7'
      }),
      cssnano({
        zindex: false
      })

    ]
  }
}

export default () => {
  const mapComponent = (name) => {
    return [
      {
        input: baseFolder + componentsFolder + `${name}/index.ts`,
        external: ['vue'],
        output: {
          format: 'umd',
          name: capitalize(name),
          file: `dist/components/${name}/index.js`,
          exports: 'named',
          globals: {
            vue: 'Vue'
          }
        },
        plugins: [
          typescript(),
          url({
            include: [
              '**/*.svg',
              '**/*.png',
              '**/*.gif',
              '**/*.jpg',
              '**/*.jpeg'
            ]
          }),
          node({
            extensions: ['.vue', '.js', '.ts']
          }),
          cjs(),
          vue(vuePluginConfig),
          css(),
          babel(babelConfig)
        ]
      }
    ]
  }

  let config = [
    {
      input: entries,
      external: ['vue'],
      output: {
        format: 'esm',
        dir: 'dist/esm'
      },
      plugins: [
        typescript(),
        cjs(),
        url({
          include: [
            '**/*.svg',
            '**/*.png',
            '**/*.gif',
            '**/*.jpg',
            '**/*.jpeg'
          ]
        }),
        node({
          extensions: ['.vue', '.js', '.ts']
        }),
        vue(vuePluginConfig),
        css(),
        babel(babelConfig),
        analyze(),
        terser({
          output: {
            comments: '/^!/'
          },
          compress: {
            defaults: true
          }
        })
      ]
    },
    {
      input: entries,
      external: ['vue'],
      output: {
        format: 'cjs',
        dir: 'dist/cjs',
        exports: 'named'
      },
      plugins: [
        typescript(),
        url({
          include: [
            '**/*.svg',
            '**/*.png',
            '**/*.gif',
            '**/*.jpg',
            '**/*.jpeg'
          ]
        }),
        node({
          extensions: ['.vue', '.js', '.ts']
        }),
        vue(vuePluginConfig),
        css(),
        babel(babelConfig),
        cjs()
      ]
    },
    // {
    //   input: 'src/index.ts',
    //   external: ['vue'],
    //   output: {
    //     format: 'umd',
    //     name: capitalize('vu'),
    //     file: 'dist/vueslib.js',
    //     exports: 'named',
    //     globals: {
    //       vue: 'Vue'
    //     }
    //   },
    //   plugins: [
    //     typescript(),
    //     url({
    //       include: [
    //         '**/*.svg',
    //         '**/*.png',
    //         '**/*.gif',
    //         '**/*.jpg',
    //         '**/*.jpeg'
    //       ]
    //     }),
    //     node({
    //       extensions: ['.vue', '.js', '.ts']
    //     }),
    //     vue(vuePluginConfig),
    //     babel(babelConfig),
    //     cjs()
    //   ]
    // },
    {
      input: 'src/index.ts',
      external: ['vue'],
      output: {
        format: 'esm',
        file: 'dist/vueslib.esm.js'
      },
      plugins: [
        typescript(),
        url({
          include: [
            '**/*.svg',
            '**/*.png',
            '**/*.gif',
            '**/*.jpg',
            '**/*.jpeg'
          ]
        }),
        node({
          extensions: ['.vue', '.js', '.ts', '.css']
        }),
        vue(vuePluginConfig),
        css(),
        babel(babelConfig),
        cjs()
      ]
    },
    // individual components
    ...components.map((f) => mapComponent(f)).reduce((r, a) => r.concat(a), [])

  ]

  if (process.env.MINIFY === 'true') {
    config = config.filter((c) => !!c.output.file)
    config.forEach((c) => {
      c.output.file = c.output.file.replace(/\.js/g, '.min.js')
      c.plugins.push(terser({
        output: {
          comments: '/^!/'
        },
        compress: {
          defaults: true
        }
      }))
    })
  }
  return config
}

ERROR SCREENSHOT Error while building library using rollup config

Component

<template>
<!-- @css/_app-partials.css-->
<div>
    <p class="yellow" @click="test()"> I am Dummy Component
      <span class="reda">asdasdas</span>
    </p>
    <span class="red">asdasdas</span>
    <img :src="require('../../assets/img/icons/download.jpeg')" />
    <div class="imgtest">
    </div>
</div>
</template>

<script lang="ts">
import { defineComponent, PropType } from 'vue'

export default defineComponent({
  name: 'DummyComponent',
  data () {
    return {
      text1: 'I am Text Component'
    }
  },
  props: {
    isValid: {
      type: Boolean,
      default: false
    },
    msg: {
      type: Object as PropType<{foo: string; bar: string}>
    }
  },
  methods: {
    test (): void {
      console.log('test1', this.$props.msg)
    }
  }
})

</script>

<style lang="postcss" scoped>
@import '../../assets/styles/css/_app-partials.css';

.yellow {
    color: red;

    .reda {
        color: $black;
    }
}

.red {
    color: green;
}

.imgtest {
    background-image: url('../../assets/img/icons/star-half.svg');
    background-size: 100%;
    width: 100px;
    height: 100px;
}
</style>

github repository link https://github.com/shubhadip/vue-typescript-component-library

Author:shubh,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/64438777/trying-to-build-vue-component-library-using-rollup-and-vuejs-3
shubh :

I got this working by changing lang="postcss" to lang="css" and then tweaking rollup-plugin-vue options which inlined the css on the components and to generate css in separate file had to use rollup-plugin-css-only.Working code is there in\nGithub",
2020-10-24T11:36:00
yy