zoukankan      html  css  js  c++  java
  • vue-loader处理vue文件

    转自:https://www.cnblogs.com/walkermag/p/13494794.html

    loader:"vue-loader" ,引导vue文件被vue-loader/lib/index.js处理
    第一步:解析vue文件
    const utils = require('@vue/component-compiler-utils')
    utils.parse(.vue文件),返回一个json:

    Copy
    {
      "template": {
        "type": "template",
        "content": "
    <div @click="setName">
        app
    </div>
    ",
        "start": 10,
        "attrs": {},
        "end": 61
      },
      "script": {
        "type": "script",
        "content": "//
    //
    //
    //
    //
    //
    
    export default {
        name: "app",
        methods:{
            setName(){
                console.log('my name');
            }
        }
    }
    ",
        "start": 82,
        "attrs": {},
        "end": 236
      },
      "styles": [
        {
          "type": "style",
          "content": "
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    div{
         300px;
    }
    ",
          "start": 261,
          "attrs": {
            "scoped": true
          },
          "scoped": true,
          "end": 299
        }
      ],
      "customBlocks": [],
      "errors": []
    }
    

    第二步:生成代码
    在vue-loader/lib/index.js中有这样的一个代码:

    Copy
    let code = `
    ${templateImport}
    ${scriptImport}
    ${stylesCode}
    
    
    /*   */
    /* normalize component */ 
    /* normalizer 函数式在chrome中执行,并不是在node中执行*/
    import normalizer from ${stringifyRequest(`!${componentNormalizerPath}`)}
    var component = normalizer(
      script,
      render,
      staticRenderFns,
      ${hasFunctional ? `true` : `false`},
      ${/injectStyles/.test(stylesCode) ? `injectStyles` : `null`},
      ${hasScoped ? JSON.stringify(id) : `null`},
      ${isServer ? JSON.stringify(hash(request)) : `null`}
      ${isShadow ? `,true` : ``}
    )
      `.trim() + `
    `
    code += `
    export default component.exports`
    

    这个模板字符串最终形式如下:
    这是一个模块 有import 和export ,和我们自己写的代码一样。

    Copy
    import { render, staticRenderFns } from "./app.vue?vue&type=template&id=6940f262&scoped=true&"
    import script from "./app.vue?vue&type=script&lang=js&"
    export * from "./app.vue?vue&type=script&lang=js&"
    import style0 from "./app.vue?vue&type=style&index=0&id=6940f262&scoped=true&lang=css&"
    
    import normalizer from "!../../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js"
    var component = normalizer(
      script,
      render,
      staticRenderFns,
      false,
      null,
      "6940f262",
      null
    )
    export default component.exports
    

    这样的代码被webpack接收之后发现有import语句,重新调用vue-loader第二次对同一个vue文件的处理。

    不过这次query上有了type类型,一进到vue-loader就被截胡了,直接根据type参数跳转到另外的loader处理。跳转代码如下:

    Copy
    if (incomingQuery.type) {
      return selectBlock(
        descriptor,
        loaderContext,
        incomingQuery,
        !!options.appendExtension
      )
    }
    

    另外loader是从哪里来的呢,这就要说到new VueLoaderPlugin()的用意了。
    VueLoaderPlugin的用处是利用webpack钩子在旧rules上添加了其他loader。
    如果type=script,最终的loader如下:

    Copy
    -!../../../node_modules/cache-loader/dist/cjs.js??ref--12-0
    !../../../node_modules/babel-loader/lib/index.js
    !../../../node_modules/cache-loader/dist/cjs.js??ref--0-0
    !../../../node_modules/vue-loader/lib/index.js??vue-loader-options
    !./topnav.vue?vue&type=script&lang=js&"
    

    如果type=template,最终的loader如下:

    Copy
    -!cache-loader?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"57422ecc-vue-loader-template"}
    !../../../node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options
    !../../../node_modules/cache-loader/dist/cjs.js??ref--0-0
    !../../../node_modules/vue-loader/lib/index.js??vue-loader-options
    !./history.vue?vue&type=template&id=f89b51d2&scoped=true&"
    

    如果type=style,最终的loader如下:

    Copy
    -!../../../../node_modules/vue-style-loader/index.js??ref--6-oneOf-1-0
    !../../../../node_modules/css-loader/index.js??ref--6-oneOf-1-1
    !../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js
    !../../../../node_modules/postcss-loader/src/index.js??ref--6-oneOf-1-2
    !../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0
    !../../../../node_modules/vue-loader/lib/index.js??vue-loader-options
    !./voice.vue?vue&type=style&index=0&id=b09c9dcc&scoped=true&lang=css&"
    

    1.加⼊!前缀, 不使⽤config loader中的normal loader,例如require('!a-loader!./a.j s');
    2.加⼊!!前缀,不使⽤config loader中的pre loader,normal loader,post loader,例如 require('!!a-loader!./a.js');
    3.加⼊-!前缀,不使⽤config loader中的normal loader,pre loader,例如require('-!a -loader!./a.js');

    上面的loader处理之后分别会生成如下的代码:
    utils.compileTemplate处理template,返回值被 normalizer的 render, staticRenderFns接收

    Copy
    {
      ast: {
        type: 1,
        tag: 'div',
        attrsList: [ [Object] ],
        attrsMap: { '@click': 'setName', class: 'sdsd' },
        rawAttrsMap: {},
        parent: undefined,
        children: [ [Object], [Object] ],
        plain: false,
        staticClass: '"sdsd"',
        hasBindings: true,
        events: { click: [Object] },
        static: false,
        staticRoot: false
      },
      code: 'var render = function() {
    ' +
        '  var _vm = this
    ' +
        '  var _h = _vm.$createElement
    ' +
        '  var _c = _vm._self._c || _h
    ' +
        '  return _c("div", { staticClass: "sdsd", on: { click: _vm.setName } }, [
    ' +
        '    _vm._v("\n    app\n    "),
    ' +
        '    _c("img", { attrs: { src: "./a.png", alt: "" } })
    ' +
        '  ])
    ' +
        '}
    ' +
        'var staticRenderFns = []
    ' +
        'render._withStripped = true
    ',
      source: '
    ' +
        '<div @click="setName" class="sdsd">
    ' +
        '    app
    ' +
        '    <img src="./a.png" alt="">
    ' +
        '</div>
    ',
      tips: [],
      errors: []
    }
    
    const { code } = compiled
    return code + `
    export { render, staticRenderFns }`
    

    utils.compiledStyle处理的结果如下, 返回值被 normalizer的 style0接收

    Copy
    const { code, map, errors } = {
      code: '
    div[data-v-12]{
         300px;
    }
    p[data-v-12]{
        background: red;
    }
    ',
      map: undefined,
      errors: [],
      rawResult: LazyResult {
        stringified: true,
        processed: true,
        result: Result {
          processor: [Processor],
          messages: [],
          root: [Root],
          opts: [Object],
          css: '
    ' +
            'div[data-v-12]{
    ' +
            '     300px;
    ' +
            '}
    ' +
            'p[data-v-12]{
    ' +
            '    background: red;
    ' +
            '}
    ',
          map: undefined,
          lastPlugin: [Function]
        }
      }
    }
    this.callback(null, code, map)
    

    脚本部分没有添加额外的处理,直接返回了vue文件中的script部分,返回值被 normalizer的 script接收

    最后回到normalizer,这个在浏览器执行的方法会接收到如下参数:
    script: 就是在vue组件中export default中定义的所有内容
    render: 由template生成的render函数,在上面能看到
    staticRenderFns :由template生成,上面能看到
    false:代表不是函数组件
    null: 代表是否在页面插入组件行内样式,此处没有使用sytle-loader处理,结果为null
    6940f262 : 组件中样式的scopeId

    如此一个组件就编译完了。
    中间的一些状态可以执行这个文件地址

  • 相关阅读:
    C#汉字转拼音(支持多音字)
    第15组构建之法团队心得
    初读《构建之法》之所感
    《构建之法》第二章自习之所感
    编程之美1的数目
    c# 将json转换为DataTable
    easyui datagrid deleteRow(删除行)的BUG
    sql 数据库 清空后让表的id从1开始等数据库操作
    sqlite字段类型说明
    webrequest、httpwebrequest、webclient、HttpClient 四个类的区别
  • 原文地址:https://www.cnblogs.com/jacksplwxy/p/14968533.html
Copyright © 2011-2022 走看看