要解决的问题

如何用更高阶的编程语言来驱动机器减少工作量

解决方案

用高阶编程语言编写代码,然后转换成机器直接支持的代码,从而允许利用机器不直接支持的抽象模式来减少工作量

构成

构成 解释
source 源代码
object 目标文件,需要静态链接才能变成executable
executable 可执行文件
compiler 编译器,把 source 编译成 object,或者一步到位变成 executable

解决方案案例

tsc

typescript 提供了两类编程上的便利

  • 给 javascript 增加了类型
  • 把高版本的 javascript 编译为低版本的 javascript 以兼容更多的 executor

source.ts

let messages: string[] = ['hello', 'world']
for (let elem of messages) {
  console.log(elem)
}

build.sh

# --target ES3 把高版本的 emcascript 编译为最初版的 javascript
tsc --target ES3 --outFile executable.js source.ts

executable.js

// /opt/my_pkg/source.ts
var messages = ['hello', 'world'];
for (var _i = 0, messages_1 = messages; _i < messages_1.length; _i++) {
    var elem = messages_1[_i];
    console.log(elem);
}

可以看到类型信息没有了, for of 的语法被编译成了等价的普通的 for 循环

构成 对应
source source.ts
executable executable.js
compiler tsc
executor node.js 或者浏览器

rustc

rust 提供了更灵活和安全的类型系统来辅助描述驱动机器的逻辑

hello.rs

fn main() {
    let msgs = ["Hello", "World"];
    for msg in &msgs {
        println!("{}", msg);
    }
}

build.sh

rustc hello.rs

./hello

# Output:
# Hello
# World

编译出来的是二进制的可执行文件,运行在CPU上

构成 对应
source hello.rs
executable ./hello
compiler rustc
executor CPU

vue-loader

webpack/vue-loader/vue-template-compiler 组合成了一个完整的编译器。 它可以把一个 .vue 单文件组件编译成 javascript 写成的 render 函数。 .vue 单文件组件,可以使用 vue 的模板语法,比 javascript 渲染 dom 的写法更可读。

hello.vue

<template>
    <div>
        <ul>
            <li v-for="item in items">{{ item }}</li>
        </ul>
    </div>
</template>
<script>
    module.exports = {
        props: ['items']
    }
</script>

webpack.config.js

// webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
    mode: 'development',
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            }
        ]
    },
    plugins: [
        // 请确保引入这个插件来施展魔法
        new VueLoaderPlugin()
    ],
    externals: {
        vue: 'vue'
    },
    output: {
        library: 'hello',
        libraryTarget: 'var'
    }
}

build.sh

webpack-cli --mode development src/hello.vue --output dist/hello.js

编译出来的 hello.js 文件是这个样子的。它全局定义了 hello 这个变量。

hello.js

var hello =
/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = "./src/hello.vue");
/******/ })
/************************************************************************/
/******/ ({

/***/ "../../node_modules/vue-loader/lib/index.js?!./src/hello.vue?vue&type=script&lang=js&":
/*!*********************************************************************************************************************************!*\
  !*** /home/xiaoju/workspace/toolchain/node_modules/vue-loader/lib??vue-loader-options!./src/hello.vue?vue&type=script&lang=js& ***!
  \*********************************************************************************************************************************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("//\n//\n//\n//\n//\n//\n//\n\nmodule.exports = {\n    props: ['items']\n}\n\n\n//# sourceURL=webpack://hello/./src/hello.vue?/home/xiaoju/workspace/toolchain/node_modules/vue-loader/lib??vue-loader-options");

/***/ }),

/***/ "../../node_modules/vue-loader/lib/loaders/templateLoader.js?!../../node_modules/vue-loader/lib/index.js?!./src/hello.vue?vue&type=template&id=be4ac86e&":
/*!**************************************************************************************************************************************************************************************************************************************************!*\
  !*** /home/xiaoju/workspace/toolchain/node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!/home/xiaoju/workspace/toolchain/node_modules/vue-loader/lib??vue-loader-options!./src/hello.vue?vue&type=template&id=be4ac86e& ***!
  \**************************************************************************************************************************************************************************************************************************************************/
/*! exports provided: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n  var _vm = this\n  var _h = _vm.$createElement\n  var _c = _vm._self._c || _h\n  return _c(\"div\", [\n    _c(\n      \"ul\",\n      _vm._l(_vm.items, function(item) {\n        return _c(\"li\", [_vm._v(_vm._s(item))])\n      }),\n      0\n    )\n  ])\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack://hello/./src/hello.vue?/home/xiaoju/workspace/toolchain/node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!/home/xiaoju/workspace/toolchain/node_modules/vue-loader/lib??vue-loader-options");

/***/ }),

/***/ "../../node_modules/vue-loader/lib/runtime/componentNormalizer.js":
/*!***************************************************************************************************!*\
  !*** /home/xiaoju/workspace/toolchain/node_modules/vue-loader/lib/runtime/componentNormalizer.js ***!
  \***************************************************************************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return normalizeComponent; });\n/* globals __VUE_SSR_CONTEXT__ */\n\n// IMPORTANT: Do NOT use ES2015 features in this file (except for modules).\n// This module is a runtime utility for cleaner component module output and will\n// be included in the final webpack user bundle.\n\nfunction normalizeComponent (\n  scriptExports,\n  render,\n  staticRenderFns,\n  functionalTemplate,\n  injectStyles,\n  scopeId,\n  moduleIdentifier, /* server only */\n  shadowMode /* vue-cli only */\n) {\n  // Vue.extend constructor export interop\n  var options = typeof scriptExports === 'function'\n    ? scriptExports.options\n    : scriptExports\n\n  // render functions\n  if (render) {\n    options.render = render\n    options.staticRenderFns = staticRenderFns\n    options._compiled = true\n  }\n\n  // functional template\n  if (functionalTemplate) {\n    options.functional = true\n  }\n\n  // scopedId\n  if (scopeId) {\n    options._scopeId = 'data-v-' + scopeId\n  }\n\n  var hook\n  if (moduleIdentifier) { // server build\n    hook = function (context) {\n      // 2.3 injection\n      context =\n        context || // cached call\n        (this.$vnode && this.$vnode.ssrContext) || // stateful\n        (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional\n      // 2.2 with runInNewContext: true\n      if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {\n        context = __VUE_SSR_CONTEXT__\n      }\n      // inject component styles\n      if (injectStyles) {\n        injectStyles.call(this, context)\n      }\n      // register component module identifier for async chunk inferrence\n      if (context && context._registeredComponents) {\n        context._registeredComponents.add(moduleIdentifier)\n      }\n    }\n    // used by ssr in case component is cached and beforeCreate\n    // never gets called\n    options._ssrRegister = hook\n  } else if (injectStyles) {\n    hook = shadowMode\n      ? function () { injectStyles.call(this, this.$root.$options.shadowRoot) }\n      : injectStyles\n  }\n\n  if (hook) {\n    if (options.functional) {\n      // for template-only hot-reload because in that case the render fn doesn't\n      // go through the normalizer\n      options._injectStyles = hook\n      // register for functioal component in vue file\n      var originalRender = options.render\n      options.render = function renderWithStyleInjection (h, context) {\n        hook.call(context)\n        return originalRender(h, context)\n      }\n    } else {\n      // inject component registration as beforeCreate hook\n      var existing = options.beforeCreate\n      options.beforeCreate = existing\n        ? [].concat(existing, hook)\n        : [hook]\n    }\n  }\n\n  return {\n    exports: scriptExports,\n    options: options\n  }\n}\n\n\n//# sourceURL=webpack://hello//home/xiaoju/workspace/toolchain/node_modules/vue-loader/lib/runtime/componentNormalizer.js?");

/***/ }),

/***/ "./src/hello.vue":
/*!***********************!*\
  !*** ./src/hello.vue ***!
  \***********************/
/*! no static exports found */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _hello_vue_vue_type_template_id_be4ac86e___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./hello.vue?vue&type=template&id=be4ac86e& */ \"./src/hello.vue?vue&type=template&id=be4ac86e&\");\n/* harmony import */ var _hello_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./hello.vue?vue&type=script&lang=js& */ \"./src/hello.vue?vue&type=script&lang=js&\");\n/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in _hello_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__) if(__WEBPACK_IMPORT_KEY__ !== 'default') (function(key) { __webpack_require__.d(__webpack_exports__, key, function() { return _hello_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[key]; }) }(__WEBPACK_IMPORT_KEY__));\n/* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n\n\n/* normalize component */\n\nvar component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(\n  _hello_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n  _hello_vue_vue_type_template_id_be4ac86e___WEBPACK_IMPORTED_MODULE_0__[\"render\"],\n  _hello_vue_vue_type_template_id_be4ac86e___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"],\n  false,\n  null,\n  null,\n  null\n  \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"src/hello.vue\"\n/* harmony default export */ __webpack_exports__[\"default\"] = (component.exports);\n\n//# sourceURL=webpack://hello/./src/hello.vue?");

/***/ }),

/***/ "./src/hello.vue?vue&type=script&lang=js&":
/*!************************************************!*\
  !*** ./src/hello.vue?vue&type=script&lang=js& ***!
  \************************************************/
/*! no static exports found */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_vue_loader_lib_index_js_vue_loader_options_hello_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/vue-loader/lib??vue-loader-options!./hello.vue?vue&type=script&lang=js& */ \"../../node_modules/vue-loader/lib/index.js?!./src/hello.vue?vue&type=script&lang=js&\");\n/* harmony import */ var _node_modules_vue_loader_lib_index_js_vue_loader_options_hello_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_vue_loader_lib_index_js_vue_loader_options_hello_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__);\n/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in _node_modules_vue_loader_lib_index_js_vue_loader_options_hello_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__) if(__WEBPACK_IMPORT_KEY__ !== 'default') (function(key) { __webpack_require__.d(__webpack_exports__, key, function() { return _node_modules_vue_loader_lib_index_js_vue_loader_options_hello_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0__[key]; }) }(__WEBPACK_IMPORT_KEY__));\n /* harmony default export */ __webpack_exports__[\"default\"] = (_node_modules_vue_loader_lib_index_js_vue_loader_options_hello_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_0___default.a); \n\n//# sourceURL=webpack://hello/./src/hello.vue?");

/***/ }),

/***/ "./src/hello.vue?vue&type=template&id=be4ac86e&":
/*!******************************************************!*\
  !*** ./src/hello.vue?vue&type=template&id=be4ac86e& ***!
  \******************************************************/
/*! exports provided: render, staticRenderFns */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_hello_vue_vue_type_template_id_be4ac86e___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!../../../node_modules/vue-loader/lib??vue-loader-options!./hello.vue?vue&type=template&id=be4ac86e& */ \"../../node_modules/vue-loader/lib/loaders/templateLoader.js?!../../node_modules/vue-loader/lib/index.js?!./src/hello.vue?vue&type=template&id=be4ac86e&\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_hello_vue_vue_type_template_id_be4ac86e___WEBPACK_IMPORTED_MODULE_0__[\"render\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return _node_modules_vue_loader_lib_loaders_templateLoader_js_vue_loader_options_node_modules_vue_loader_lib_index_js_vue_loader_options_hello_vue_vue_type_template_id_be4ac86e___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"]; });\n\n\n\n//# sourceURL=webpack://hello/./src/hello.vue?");

/***/ })

/******/ });

其中 eval 的关键源代码,就是把 vue 模板编译出来的 javascript 代码

__webpack_require__.r(__webpack_exports__);
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "render", function() { return render; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "staticRenderFns", function() { return staticRenderFns; });
var render = function() {
  var _vm = this
  var _h = _vm.$createElement
  var _c = _vm._self._c || _h
  return _c("div", [
    _c(
      "ul",
      _vm._l(_vm.items, function(item) {
        return _c("li", [_vm._v(_vm._s(item))])
      }),
      0
    )
  ])
}
var staticRenderFns = []
render._withStripped = true

使用这个编译好的 hello.js 文件

index.html

<html>
<head>
    <script src="https://unpkg.com/vue@2.6.8/dist/vue.js"></script>
    <script src="dist/hello.js"></script>
</head>
<body>
<div id="app">
    <hello :items="['a', 'b', 'c']"></hello>
</div>
<script>
    new Vue({
        components: {
            hello: hello.default
        },
        el: '#app'
    })
</script>
</body>
</html>

rollup-plugin-vue

rollup/rollup-plugin-vue/vue-template-compiler 组合成了一个完整的编译器。 它可以把一个 .vue 单文件组件编译成 javascript 写成的 render 函数。 .vue 单文件组件,可以使用 vue 的模板语法,比 javascript 渲染 dom 的写法更可读。

hello.vue

<template>
    <div>
        <ul>
            <li v-for="item in items">{{ item }}</li>
        </ul>
    </div>
</template>
<script>
    export default {
        props: ['items']
    }
</script>

rollup.config.js

import vue from 'rollup-plugin-vue'
import commonjs from 'rollup-plugin-commonjs';

export default {
    input: 'src/hello.vue',
    output: {
        format: 'esm',
        file: 'dist/hello.js'
    },
    plugins: [
        commonjs(),
        vue()
    ]
}

build.sh

rollup -c

编译出来的 hello.js 文件是这个样子的。它是一个 es6 的 module

hello.js

//
//
//
//
//
//
//

var script = {
    props: ['items']
};

function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier
/* server only */
, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {
  if (typeof shadowMode !== 'boolean') {
    createInjectorSSR = createInjector;
    createInjector = shadowMode;
    shadowMode = false;
  } // Vue.extend constructor export interop.


  var options = typeof script === 'function' ? script.options : script; // render functions

  if (template && template.render) {
    options.render = template.render;
    options.staticRenderFns = template.staticRenderFns;
    options._compiled = true; // functional template

    if (isFunctionalTemplate) {
      options.functional = true;
    }
  } // scopedId


  if (scopeId) {
    options._scopeId = scopeId;
  }

  var hook;

  if (moduleIdentifier) {
    // server build
    hook = function hook(context) {
      // 2.3 injection
      context = context || // cached call
      this.$vnode && this.$vnode.ssrContext || // stateful
      this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext; // functional
      // 2.2 with runInNewContext: true

      if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
        context = __VUE_SSR_CONTEXT__;
      } // inject component styles


      if (style) {
        style.call(this, createInjectorSSR(context));
      } // register component module identifier for async chunk inference


      if (context && context._registeredComponents) {
        context._registeredComponents.add(moduleIdentifier);
      }
    }; // used by ssr in case component is cached and beforeCreate
    // never gets called


    options._ssrRegister = hook;
  } else if (style) {
    hook = shadowMode ? function () {
      style.call(this, createInjectorShadow(this.$root.$options.shadowRoot));
    } : function (context) {
      style.call(this, createInjector(context));
    };
  }

  if (hook) {
    if (options.functional) {
      // register for functional component in vue file
      var originalRender = options.render;

      options.render = function renderWithStyleInjection(h, context) {
        hook.call(context);
        return originalRender(h, context);
      };
    } else {
      // inject component registration as beforeCreate hook
      var existing = options.beforeCreate;
      options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
    }
  }

  return script;
}

var normalizeComponent_1 = normalizeComponent;

/* script */
const __vue_script__ = script;

/* template */
var __vue_render__ = function() {
  var _vm = this;
  var _h = _vm.$createElement;
  var _c = _vm._self._c || _h;
  return _c("div", [
    _c(
      "ul",
      _vm._l(_vm.items, function(item) {
        return _c("li", [_vm._v(_vm._s(item))])
      }),
      0
    )
  ])
};
var __vue_staticRenderFns__ = [];
__vue_render__._withStripped = true;

  /* style */
  const __vue_inject_styles__ = undefined;
  /* scoped */
  const __vue_scope_id__ = undefined;
  /* module identifier */
  const __vue_module_identifier__ = undefined;
  /* functional template */
  const __vue_is_functional_template__ = false;
  /* style inject */
  
  /* style inject SSR */
  

  
  var hello = normalizeComponent_1(
    { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
    __vue_inject_styles__,
    __vue_script__,
    __vue_scope_id__,
    __vue_is_functional_template__,
    __vue_module_identifier__,
    undefined,
    undefined
  );

export default hello;

通过 package.json 发布出去,可以被做为一个 es6 模块引用

package.json

{
  "private": true,
  "name": "@compiler/rollup-plugin-vue",
  "version": "1.0.0",
  "scripts": {
    "build": "./build.sh"
  },
  "module": "dist/hello.js",
  "dependencies": {
    "rollup": "^1.6.0"
  },
  "devDependencies": {
    "rollup-plugin-commonjs": "^9.2.1",
    "rollup-plugin-vue": "^4.7.2"
  }
}

通过 es6 模块引用编译好的 .vue 文件

App.vue

<template>
    <div>
        <hello :items="['a','b','c']"></hello>
    </div>
</template>
<script>
    import hello from '@compiler/rollup-plugin-vue'
    export default {
        components: {hello}
    }
</script>