0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

.vueファイルのesm.js化及びwebcomponent.esm.js化に成功

Posted at

ファイル名の意図

  • TodoApp: Exampleファイル。
  • TodoApp.vue: 通常のvueファイル
  • TodoApp.vue.esm.js: vueファイルをjsに変換したもの。esmodule形式。vueコンポーネントがexportされている。
  • TodoApp.vue.shadowmode.esm.js: vueファイルをjsに変換したもの。esmodule形式。vueコンポーネントがexportされている。styleがheadではなくtemplateにinjectされる番(shadowdomのため)。
  • TodoApp.esm.js: vueコンポーネントをwebcomponentに変換したもの。esmodule形式。
  • todo-app.js: webcomponentをcustomeElement.defineした、そのままタグとして利用できるもの。

TodoApp.vue -> TodoApp.vue.esm.js

rollup + rollup-plugin-vue

rollup.config.js
import VuePlugin from 'rollup-plugin-vue'

export default {
  input: 'TodoApp.vue'
  output: {
    file: 'TodoApp.vue.esm.js',
    format: 'esm'
  },
  plugins: [
    VuePlugin()
  ]
}

TodoApp.vue -> TodoApp.vue.shadowmode.esm.js

webpackでvue-loaderを使えばshadowmode: trueというoptionを使うだけで良いのだが、webpackではesmは作れない。
rollupで頑張る。
今回の記事のキモ。

via: https://github.com/vuejs/rollup-plugin-vue/issues/284#issuecomment-499009722

rollup.config.js
import VuePlugin from 'rollup-plugin-vue'

export default {
  input: 'TodoApp.vue'
  output: {
    file: 'TodoApp.vue.shadowmode.esm.js',
    format: 'esm'
  },
  plugins: [
    VuePlugin({
      normalizer: '~./normalize-component.js'
    })
  ]
}
normalize-component.js
'use strict';
function createInjectorShadow(shadow) {
    return (inject, { source, map, media }) => {
        const style = document.createElement('style');
        style.appendChild(document.createTextNode(source));
        shadow.appendChild(style);
    };
}

function normalizeComponent(
    template,
    style,
    script,
    scopeId,
    isFunctionalTemplate,
) {
    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 (style) {
        hook = function() {
            style.call(
                this,
                createInjectorShadow(this.$root.$options.shadowRoot),
            );
        };
    }

    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;
}

export default normalizeComponent;

TodoApp.vue.shadowmode.esm.js -> TodoApp.esm.js

これは単にファイルを作るだけで、rollupは使わない。

TodoApp.esm.js
import Vue from 'vue/dist/vue.esm.js'
import wrap from '@vue/web-component-wrapper'
import TodoAppVueComponent from './TodoApp.vue.js'

const TodoApp = wrap(Vue, TodoAppVueComponent)

export default TodoApp

TodoApp.esm.js -> todo-app.js

これは単にファイルを作るだけで、rollupは使わない。

todo-app.js
import TodoApp from './TodoApp.js'

window.customElements.define('todo-app', TodoApp);

使用方法

ここで作ったすべてのファイルは、通常のフロントエンドnodeパッケージと同様に、そのままwebpackなどに読み込ませて使えるはず。

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?