[Transfer] Differences between compilation output files

The Vue source code uses rollup as the bundler. When looking at the Vue source code, it is found that: npm script corresponds to different build options. This also corresponds to the different packages produced after the final package build.

Different from other libraries, why does Vue output different types of packages in the final package and build link? Next, we simply analyze it through the source code of Vue and the corresponding build configuration.

Since Vue is built based on  rollup  , let's take a brief look at the bundler rollup: rollup uses the ES Module specification instead of CommonJS by default, so if you use rollup as a build tool in your project, you can use it with confidence ES Module specification, but if you want to introduce a third package that only follows the CommonJs specification, you also need to use related plugins, which will help you convert the CommonJs specification code to ES Module. Thanks to ES Module, rollup performs static analysis and tree-shaking before building. Please poke me for a description of tree-shaking   . In the build output phase, rollup provides a variety of file output types:

  • iife : execute the function immediately

  • cjs : file output following CommonJs Module specification

  • amd : file output following AMD Module specification

  • umd : support file output of external links / CommonJs Module / AMD Module specification

  • es : Compile multiple ES6 Module-compliant files into one ES6 Module

Next we'll look at a few different versions of Vue built with rollup (the one used for the browser).

npm run dev corresponds to

rollup -w -c build/config.js --environment TARGET:web-full-dev

The configuration information corresponding to rollup is:

// Runtime+compiler development build (Browser)
 'web-full-dev': {
    entry: resolve('web/runtime-with-compiler.js'),  dest: resolve('dist/vue.js'),  format: 'umd',  env: 'development',  alias: { he: './entity-decoder' }, banner },

For the umd format code output in the development environment, the entry file is runtime-with-compiler.js. This entry file is a unified package of Vue's build-time and runtime codes. By looking at this entry file, we notice arrive

...
import { compileToFunctions } from './compiler/index'
...

const mount = Vue.prototype.$mount
Vue.prototype.$mount = function () {
     }

We found that in this file, the originally defined Vue.prototype.$mount method is first cached, and then this method is rewritten. In the rewritten method, first determine whether there is a custom render function, if there is a self-defined render function If the defined render function is defined, Vue will not compile the template through the built-in compiler and generate the render function. However, if there is no custom render function, the compiler will be called to compile the template you define and generate a render function, so the code built through this rollup configuration supports both custom render functions and template template compilation:

// Compile the template into a render function and mount it to the options property of the vm instance
       const { render, staticRenderFns } = compileToFunctions(template, {
        shouldDecodeNewlines,
        delimiters: options.delimiters
      }, this)
      options.render = render
      options.staticRenderFns = staticRenderFns
      
      ...
    // Call the previously cached mount function, TODO: Please poke me about what happened in this function and return mount.call( this, el, hydrating)

Next, let's look at the second construction method:

npm run dev:cjs corresponding build script

rollup -w -c build/config.js --environment TARGET:web-runtime-cjs

The configuration information corresponding to rollup is:

// Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify
  'web-runtime-cjs': {
    entry: resolve('web/runtime.js'),
    dest: resolve('dist/vue.runtime.common.js'), format: 'cjs', banner }

The final compiled output file follows the CommonJs Module and only contains the runtime part of the code, which can be directly loaded by webpack 1.x and Browserify. Its corresponding entry file is runtime.js:

import Vue from './runtime/index'

export default Vue

The Vue.prototye.$mount method is not overridden here, so in the life cycle of the vm instance, when the beforeMount stage is reached:

// root element mounted by
     vm if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }
export function mountComponent ( vm: Component, the:? Item, hydrating?: boolean ): Component { // vm.$el为真实的node vm.$el = el // 如果vm上没有挂载render函数 if (!vm.$options.render) { // 空节点 vm.$options.render = createEmptyVNode if (process.env.NODE_ENV !== 'production') { /* istanbul ignore if */ if ((vm.$options.template && vm.$options.template.charAt(0) !== '#') || vm.$options.el || el) { warn( 'You are using the runtime-only build of Vue where the template ' + 'compiler is not available. Either pre-compile the templates into ' + 'render functions, or use the compiler-included build.', vm ) } else { warn( 'Failed to mount component: template or render function not defined.', vm ) } } } // 钩子函数 callHook(vm, 'beforeMount') let updateComponent /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.performance && mark) { updateComponent = () => { const name = vm._name const id = vm._uid const startTag = `vue-perf-start:${id}` const endTag = `vue-perf-end:${id}` mark(startTag) const vnode = vm._render() mark(endTag) measure(`${name} render`, startTag, endTag) mark(startTag) vm._update(vnode, hydrating) mark(endTag) measure(`${name} patch`, startTag, endTag) } } else { // updateComponent is a listener function, new Watcher(vm, updateComponent, noop) updateComponent = () => { // Vue.prototype._render rendering function // vm._render() returns a VNode // update dom // vm._render() calls the render function, which will return a VNode. During the process of generating VNode, the getter will be dynamically calculated and pushed into dep at the same time. // Hydrating is false in the case of non-ssr vm._update(vm._render( ), hydrating) } } // Create a new _watcher object // The _watcher mounted on the vm instance is mainly to update the DOM // In the process of instantiating the watcher, updateComponent will be executed to complete the collection of dependent variables Procedure // vm/expression/cb vm._watcher = new Watcher(vm, updateComponent, noop) hydrating = false // manually mounted instance, call mounted on self // mounted is called for render-created child components in its inserted hook if (vm.$vnode ==null) { vm._isMounted = true callHook(vm, 'mounted') } return vm }

First determine whether the render function is defined on the vm instance. If not, a new empty vnode will be created and mounted on the render function. Also, if the rendering of the page is passed in the form of the root node:

new View({
       el: '#app' })

Vue will print the log information:

warn(
          'You are using the runtime-only build of Vue where the template ' +
          'compiler is not available. Either pre-compile the templates into ' +
          'render functions, or use the compiler-included build.'

It means that you are currently using only the packaged code of the runtime, and the code of the template compiler (ie build time) is not included in it. Therefore, you cannot organize your html content by hanging the root node or declarative templates, but can only use the render function to write template content. However, the error message also gives a hint that you can also choose the pre-compile precompiler tool to compile the template template into a render function (vue-loader plays this role) or use the output package that contains the compiler, That is, the package analyzed above contains both the compiler and the runtime.

The third way to build:

The build script corresponding to npm run dev:esm is:

rollup -w -c build/config.js --environment TARGET:web-runtime-esm

The entry file and the final constructed code content are the same as the second one, only the runtime part of the code is included, but the output code follows the ES Module specification. Can be loaded directly by bundlers that support ES Modules, such as webpack2 and rollup.

The fourth construction method:

The build script corresponding to npm run dev:compiler is:

rollup -w -c build/config.js --environment TARGET:web-compiler

Different from the previous 3 construction methods:

// Web compiler (CommonJS).
'web-compiler': {
    entry: resolve('web/compiler.js'),
    dest: resolve('packages/vue-template-compiler/build.js'), format: 'cjs', external: Object.keys(require('../packages/vue-template-compiler/package.json').dependencies) },

This build corresponds to a separate packaged output of compiler.js that compiles the Vue template into a render function. The final output packages/vue-template-compiler/build.js file will be released separately as a node_modules. During your development process, if you use webpack as a build tool and vue-loader, in the development and build process, vue- The loader will process the contents of the template <template> in your *.vue file through the web compiler, and compile these template strings into render functions.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324478028&siteId=291194637