11
头图

I want to solve a scenario recently. When ve-charts , I want to make a code example to demonstrate the function. After changing the code, you can intuitively see the changes in the components. In the previous version, the document used docsify , and there is a vuep . Vuep is to solve the scene I need. But the vuep version is relatively old. Vue3 components are not currently supported. So I want to independently develop a component that runs code examples.

ES Modules specification

ES modules (ESM) is the official standardized module system of JavaScript

Evolution

Before ES6, there were already familiar module loading solutions CommonJS and AMD . The former was used for the server, namely Node.js , while the latter used third-party libraries to implement browser loading modules.

In front-end engineering, CommonJS wider range of applications. We can see from three aspects:

  • NPM of the third-party modules that we rely on published on CommonJS
  • The front-end resources built by Webpack Node.js environment CommonJS
  • We write ESM code needs by Babel convert CommonJS

The good news is that browsers have begun to natively support module functions, and Node.js also continuing to support ES Modules module functions.

ESM standardization is still on the road

The difference between client and server implementation

Use ES Modules in Node.js

Starting from Node.js v13.2.0 , there are two ways to correctly parse the ESM standard module. In between, you need to add --experimental-modules to use the ESM module.

  • .mjs ending with the extension 060b759ea23615
  • With the suffix .js end of file, and in package.json declared field type to module

// esmA/index.mjs

export default esmA

// or

// esmB/index.js

export default esmB

// esmB/package.json

{

  "type": "module"

}
  • .cjs will continue to be parsed as CommonJS module

Use ES Modules in the browser

Modern browsers have native support for load ES Modules need to type="module" put <script> tab, this statement is a script module.

In this way, you can use the import and export statements in the script

<script type="module">
  // include script here
</script>

caniuse-esm

Handling dependencies in Node.js

In the modern front-end engineering development environment, package.json . After the modules are installed, all modules will be placed in the node_modules folder. For example, the description in package.json depends on lodash :

{
  "name": "test",
  "version": "0.0.1",
  "dependencies": {
    "lodash": "^4.17.21"
  }
}

Handle dependencies in the browser

Similarly, to handle the dependencies between modules in the browser, there is currently a new proposal import-maps

Define the mapping relationship between the module name and module address by declaring the attribute type of the <script> importmap

E.g:

<script type="importmap">
{
  "imports": {
    "lodash": "https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"
  }
}
</script>

Handle dependencies and use modules in the browser

importmap is still in the proposal stage. The current browser compatibility is still very slow, but it will continue to be compatible in the future. We can use es-module-shims make the browser compatible.

<!-- UNPKG -->
<script async src="https://unpkg.com/es-module-shims@0.10.1/dist/es-module-shims.js"></script>

<!-- 声明依赖 -->
<script type="importmap">
{
  "imports": {
    "app": "./src/app.js"
  }
}
</script>

<!-- 使用模块 -->
<script type="module">
import 'app'
</script>

Introduction to Vue SFC

What is Vue SFC?

In the Vue ecosystem, SFC is the abbreviation of single-file components

A Vue component is described by the extension .vue

features:

Code Example:

sfc

How to compile Vue SFC?

Vue projects need to use vue-loader or rollup-plugin-vue to compile SFC files into executable JS

Vue 2

vue-loader depends on:

  • @vue/component-compiler-utils
  • vue-style-loader

Vue 3

vue-loader@next depends on:

  • @vue/compiler-core

Vite 2

@vitejs/plugin-vue depends on:

  • @vue/compiler-sfc

@vue/compiler-sfc works

To compile a Vue SFC component, you need to compile the components template , script and style

API

                                  +--------------------+
                                  |                    |
                                  |  script transform  |
                           +----->+                    |
                           |      +--------------------+
                           |
+--------------------+     |      +--------------------+
|                    |     |      |                    |
|  facade transform  +----------->+ template transform |
|                    |     |      |                    |
+--------------------+     |      +--------------------+
                           |
                           |      +--------------------+
                           +----->+                    |
                                  |  style transform   |
                                  |                    |
                                  +--------------------+

facade module will eventually be compiled into the following component pseudo code render

// main script
import script from '/project/foo.vue?vue&type=script'
// template compiled to render function
import { render } from '/project/foo.vue?vue&type=template&id=xxxxxx'
// css
import '/project/foo.vue?vue&type=style&index=0&id=xxxxxx'

// attach render function to script
script.render = render

// attach additional metadata
// some of these should be dev only
script.__file = 'example.vue'
script.__scopeId = 'xxxxxx'

// additional tooling-specific HMR handling code
// using __VUE_HMR_API__ global

export default script

Vite & Vue SFC Playground

The official applications built on @vue/compiler-sfc Vite and Vue SFC Playground . The former runs on the server side and the latter runs on the browser side.

Vite dependencies

  • vite 2 provides Vue 3 single file component support through plug-in @vitejs/plugin-vue
  • underlying dependency @vue/compiler-sfc

Dependency of Vue SFC Playground

What is the difference between the process of compiling SFC between the two?

SFC Playground of the module in Vite is derived from the support for SSR

Vite

SFC Playground

HelloWorld.vue the difference between the two compiled 060b759ea23d39 components?

Vite

// /components/HelloWorld.vue
import {defineComponent} from "/node_modules/.vite/vue.js?v=49d3ccd8";
const _sfc_main = defineComponent({
  name: "HelloWorld",
  props: {
    msg: {
      type: String,
      required: true
    }
  }
});

import { toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "/node_modules/.vite/vue.js?v=49d3ccd8"

function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("h1", null, _toDisplayString(_ctx.msg), 1 /* TEXT */))
}

_sfc_main.render = _sfc_render
_sfc_main.__file = "/Users/xiaoyunwei/GitHub/private/slides-vite-demo/src/components/HelloWorld.vue"
export default _sfc_main

SFC Playground

// ./HelloWorld.vue
const __sfc__ = {
  name: "HelloWorld",
  props: {
    msg: {
      type: String,
      required: true
    }
  }
}

import { toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"

function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("h1", null, _toDisplayString($props.msg), 1 /* TEXT */))
}
__sfc__.render = render
__sfc__.__file = "HelloWorld.vue"
export default __sfc__

App.vue the difference between the two compiled 060b759ea23dbd components?

Vite

// ./App.vue
import {defineComponent} from "/node_modules/.vite/vue.js?v=49d3ccd8";
import HelloWorld from "/src/components/HelloWorld.vue";
const _sfc_main = defineComponent({
  name: "App",
  components: {
    HelloWorld
  }
});

import { resolveComponent as _resolveComponent, openBlock as _openBlock, createBlock as _createBlock } from "/node_modules/.vite/vue.js?v=49d3ccd8"

function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  const _component_HelloWorld = _resolveComponent("HelloWorld")

  return (_openBlock(), _createBlock(_component_HelloWorld, { msg: "Hello Vue 3 + TypeScript + Vite" }))
}

_sfc_main.render = _sfc_render
_sfc_main.__file = "/Users/xiaoyunwei/GitHub/private/slides-vite-demo/src/App.vue"
export default _sfc_main

SFC Playground

// ./App.vue
import HelloWorld from './HelloWorld.vue'

const __sfc__ = {
  name: 'App',
  components: {
    HelloWorld
  }
}

import { resolveComponent as _resolveComponent, openBlock as _openBlock, createBlock as _createBlock } from "vue"
function render(_ctx, _cache, $props, $setup, $data, $options) {
  const _component_HelloWorld = _resolveComponent("HelloWorld")

  return (_openBlock(), _createBlock(_component_HelloWorld, { msg: "Hello Vue SFC Playground" }))
}
__sfc__.render = render
__sfc__.__file = "App.vue"
export default __sfc__

It can be seen that the underlying logic is basically the same when compiling SFC.

Abstract the ability to compile SFC into ES Modules

Learn from Vue SFC Playground and built two wheels🎡

If you are interested, you can click to GitHub

vue-sfc2esm

Compile Vue SFC into ES modules.

sfc2esm

Features

  • 💪 Written based on TypeScript
  • 🌳 TreeShakable & SideEffects Free
  • 📁 Virtual file system (supports compilation of .vue/.js files).
  • 👬 Friendly error message

Core logic

  • vue-sfc2esm implements a virtual 📁 file system to record the relationship between files and codes.
  • vue-sfc2esm be based @ VUE / Compiler-SFC the SFC code into ES Modules .
  • The compiled ES Modules code can be directly used in modern browsers.

Compile the App.vue sample code:

<script type="module">
import { createApp as _createApp } from "vue"

if (window.__app__) {
  window.__app__.unmount()
  document.getElementById('app').innerHTML = ''
}

document.getElementById('__sfc-styles').innerHTML = window.__css__
const app = window.__app__ = _createApp(__modules__["DefaultDemo.vue"].default)
app.config.errorHandler = e => console.error(e)
app.mount('#app')
</script>

💡 Before using the ES Modules module, you need to introduce Vue

<script type="importmap">
  {
    "imports": { "vue": "https://cdn.jsdelivr.net/npm/vue@next/dist/vue.esm-browser.js" }
  }
</script>

vue-sfc-sandbox

vue-sfc-sandbox is vue-sfc2esm , and it is also @vue/compiler-sfc , providing real-time editing & previewing SFC sandbox components.

sfc-preivew

Features

🗳️ SFC Sandbox

  • 💪 Written based on TypeScript
  • 🌳 TreeShakable & SideEffects Free
  • 📁 Virtual file system (supports compilation of .vue/.js files)
  • 👬 Friendly error message, based on vue-sfc2esm
  • 🧪 Convert Vue SFC files to ES Modules
  • 🔌 Support external CDN, such as unpkg , jsdelivr etc.
  • 🧩 Load Import Maps .

✏️ editor panel

  • 🎨 Code editor based on codemirror 6
  • 🧑‍💻 Friendly to developers, built-in highlight code, interactive panel presents REPL sandbox environment.

👓 Preview Panel

  • ⚡️ Compile SFC files in real time
  • 🔍 View in full screen

The future and the status quo

✨ Function

  • Online real-time compilation & preview of SFC files / Vue 3 components
  • Support incoming external CDN
  • Support incoming Import Maps , incoming URL needs to be ESM

💠 Future

  • Export SFC components
  • Support real-time compilation of React components
  • Editor smart tips

💉 Pain point

  • Cannot directly use packages packaged in CommonJS or UMD format
  • The third party relies on too many requests, and there is an obvious waiting time

🖖 break

Similar project

Similar to sfc-sandbox , based on the Vue technology stack, an editor + demo tool can be provided online

  • vuep - 🎡 A component for rendering Vue components with live editor and preview.
  • demosify - Create a playground to show the demos of your projects.
  • codepan - Like codepen and jsbin but works offline (Archived).

Future front-end engineering construction

Although the browser can now be loaded using ES Modules , but it still has some above-mentioned pain points problems of.

However, today in 2021, a new batch of front-end construction tools have emerged that can be called the next generation, such as esbuild , snowpack , vite , wmr and so on.

You can take a look at this article "Comparing the New Generation of Build Tools" , which analyzes and compares the front-end next-generation build tools from the aspects of tool configuration, development services, production construction, and building SSR.

future-build-tools

Reference

Mobile reading

Follow my technical public number, you can also find this article.

xiaoluoboding

Original: https://transpile-vue-sfc-to-es-modules.vercel.app

xiaoluoboding
2.1k 声望503 粉丝

I 💗 Web Dev, 💻 I'm a Senior Frontend Engineer