Rollup从0到1上手前端组件库开发 | VUE组件编译

2,763 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

Rollup从0到1上手前端组件库开发 | VUE组件编译

上文回顾

通过上文的讲解, 我们目前已经完成了js文件的解析和编译, 下面我们一起研究一下如何解析和编译vue文件

尝试一下使用Rollup打包Vue文件

  • 首先,创建一个简单的 Vue3 组件

    在src 目录下创建 Test.vue文件

<template>
  <div class="test">{{message}}</div>
</template>

<script>
export default {
  name: "TestComponent",
  setup() {
    const message = 'hello rollup'
    return {
      message
    }
  }
}
</script>
<style scoped lang="scss">
  .test {
    color: blue;
  }
</style>
  • 在 index.js 中定义组件
import Test from './Test.vue'


export default function (Vue) {
    Vue.component(Test.name, Test)
}
  • 直接通过 npm run build 来构建
npm run build

> payfun.rollbear.view@1.0.0 build
> rollup -c rollup.config.dev.js

/Users/pm/adtech/pc/payfun.rollbear.view/src/index.js

/Users/pm/adtech/pc/payfun.rollbear.view/src/index.js → dist/payfun.rollbear.dev.js, dist/payfun.rollbear.dev.es.js...

# 报错了~!
# [!] Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)
# src/Test.vue (1:0)

Test.vue 文件在Rollup打包的默认情况下是不能支持的, 需要vue插件才能支持

接下来我们继续研究 Rollup 如何支持 vue 文件打包

安装插件

yarn add rollup-plugin-vue -D

"rollup-plugin-vue": "^6.0.0"    #6.0.0 可以支持 vue3 组件打包编译

配置文件中添加对 .vue 文件的支持

vim rollup.config.dev.js

const path = require('path')
const resolve = require("rollup-plugin-node-resolve")
const commonjs = require('rollup-plugin-commonjs')
const babel = require('rollup-plugin-babel')
const json = require('rollup-plugin-json')
// 这里 引入 vue 插件
const vue = require('rollup-plugin-vue')
const inputPath = path.resolve(__dirname, "./src/index.js") // 输入路径
const outputUmdPath = path.resolve(__dirname, "./dist/payfun.rollbear.dev.js") // 输出路径
const outputEsPath = path.resolve(__dirname, "./dist/payfun.rollbear.dev.es.js") // 输出路径
console.log(inputPath)
module.exports = {
    input: inputPath,
    output: [
        {
            file: outputUmdPath, // 输出路径
            format: 'umd', // 输出的模块协议 umd
            name: "payfunRollbear" // 模块名称
        },
        {
            file: outputEsPath, // 输出路径
            format: 'es', // 输出的模块协议 es
            name: "payfunRollbear" // 模块名称
        }
    ],
    plugins: [
        resolve(),
        commonjs(),
        babel({
            exclude: 'node_modules/**', // 指定哪些文件夹时不进行babel编译的
        }),
        json(),
        vue(), // 使用Vue插件
    ],
    external: ['decimal.js'], //表示哪些模块是外部引用, 即使开启了 resolve 这里面的模块仍然是外部引用
}

再吃尝试一下 yarn build

npm run build

> rollbear.view@1.0.0 build
> rollup -c rollup.config.dev.js

[!] Error: rollup-plugin-vue requires @vue/compiler-sfc to be present in the dependency tree.

结果发现仍然报错, 从错误信息中我们发现 rollup-plugin-vue 需要 @vue/compiler-sfc的依赖

安装 @vue/compiler-sfc

yarn add @vue/compiler-sfc -D

安装完成后我们不需要手动去使用, rollup-plugin-vue 会自动去使用

划重点!!! Rollup 的 plugin 是有序的! vue要在前面调用 , 否则就会报错

  plugins: [
        vue(),  // vue 放在最前面
        resolve(),
        commonjs(),
        babel({
            exclude: 'node_modules/**', // 指定哪些文件夹时不进行babel编译的
        }),
        json(),
        postcss({
            plugins:[]
        })
    ],

再次 yarn build

yarn build

[!] Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)
src/Test.vue?vue&type=style&index=0&id=07bdddea&scoped=true&lang.scss (2:0)
1: 
2: .test {
   ^
3:   color: blue;
4: }
Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)


此时我们发现 style 文件不能解析, 当前可以解析 .vue 文件, 但是 style部分无法识别

通过 rollup-plugin-postcss 插件 来解决 style 无法识别的问题

yarn add rollup-plugin-postcss -D

将 postcss 加到 配置中

// ...
const vue = require('rollup-plugin-vue')
// 添加 postcss 插件
const postcss = require('rollup-plugin-postcss')
// ...
module.exports = {
  // ...
	   plugins: [
        resolve(),
        commonjs(),
        babel({
            exclude: 'node_modules/**', // 指定哪些文件夹时不进行babel编译的
        }),
        json(),
        vue(),
        postcss({
            plugins:[]
        })
    ],
    // ...
}
//...

再次执行 yarn build

又报错了~!

[!] (plugin postcss) Error: You need to install one of the following packages: "node-sass", "sass" in order to process SASS files

这里发现我们需要安装 node-sasssass 两者之一

安装 sass (dart-sass)

yarn add sass -D

再次编译

created rollbear.dev.js, rollbear.dev.es.js in 2.8s
✨  Done in 5.00s.

终于成功啦!

查看ES模块编译结果

import { openBlock, createElementBlock, toDisplayString } from 'vue';

var script = {
  name: "TestComponent",
  setup: function setup() {
    var message = 'hello rollup';
    return {
      message: message
    };
  }
};

var _hoisted_1 = {
  "class": "test"
};
function render(_ctx, _cache, $props, $setup, $data, $options) {
  return openBlock(), createElementBlock("div", _hoisted_1, toDisplayString($setup.message), 1
  /* TEXT */
  );
}

function styleInject(css, ref) {
  if ( ref === void 0 ) ref = {};
  var insertAt = ref.insertAt;

  if (!css || typeof document === 'undefined') { return; }

  var head = document.head || document.getElementsByTagName('head')[0];
  var style = document.createElement('style');
  style.type = 'text/css';

  if (insertAt === 'top') {
    if (head.firstChild) {
      head.insertBefore(style, head.firstChild);
    } else {
      head.appendChild(style);
    }
  } else {
    head.appendChild(style);
  }

  if (style.styleSheet) {
    style.styleSheet.cssText = css;
  } else {
    style.appendChild(document.createTextNode(css));
  }
}

var css_248z = ".test[data-v-07bdddea] {\n  color: blue;\n}";
styleInject(css_248z);

script.render = render;
script.__scopeId = "data-v-07bdddea";
script.__file = "src/Test.vue";

function index (Vue) {
  Vue.component(script.name, script);
}

export { index as default };

因为我们用了 external: ['vue'], 所以vue源码不会打包到我们的文件当中~

至此 Vue 文件的编译就实现了~!

总结

编译 .vue 组件的步骤

  • 安装并配置 vue 插件 yarn add rollup-plugin-vue -D
  • 安装vue插件依赖 yarn add @vue/compiler-sfc -D
    • 强调 rollup 的plugin 是有执行顺序的 , vue 要放在最前面调用
  • 安装 postcss 插件用来支持 style
  • 安装 sass 用来支持 sass 预处理器

警告问题解决

在成功编译 .vue 文件是 我们发现 terminal 上有两个黄色的警告

(!) Unresolved dependencies
    # vue没用到,可以无视
(!) Missing global variable name
Use output.globals to specify browser global variable names corresponding to external modules
vue (guessing 'vue')

		# 解决方法: output 中添加 globals
output: [
        {
            file: outputUmdPath, // 输出路径
            format: 'umd', // 输出的模块协议 umd
            name: "payfunRollbear", // 模块名称
            globals: {
                vue: 'Vue'
            }
        },
]