element-ui-2.8.2-dev

176 阅读2分钟

0

学习dev环境是如何运作markdown-it.docschina.org/的 组件页面是以md格式编写的,代码中使用md-loader来解析这些文件

webpack

{
        test: /\.md$/,
        use: [
          {
            loader: 'vue-loader',
            options: {
              compilerOptions: {
                preserveWhitespace: false
              }
            }
          },
          {
            loader: path.resolve(__dirname, './md-loader/index.js')
          }
        ]
      }

step1. 用md-loader解析成vue文件 step2. 用vue-loader来解析生成的文件

md-loader

  1. markdown-it 是 Markdown 解析器 文档: markdown-it.docschina.org/
  2. markdown-it-chain 是markdown-it 可以chain 式操作
  3. markdown-it-anchor 为标题添加锚点
  4. transliteration 中文转拼音 demo : dzcpy.github.io/translitera…
//slugify 的用法
import { transliterate as tr, slugify } from 'transliteration';

tr('你好, world!');
// Ni Hao , world!
slugify('你好, world!');
// ni-hao-world
  1. markdown-it-container Plugin for creating block-level custom containers for markdown-it markdown parser. 这里用来处理 :::demo ... :::

zhuanlan.zhihu.com/p/65174076 blog.csdn.net/Ariana_l/ar…

const mdContainer = require('markdown-it-container')

module.exports = md => {
/* 由于 demo是 以下格式所有要特殊处理
:::demo 标题 
内容 
::: 
tip 和warning 都是 以下格式,没有标题,所以无需处理
:::xx
:::
*/
	md.use(mdContainer, 'demo', {
		validate(params) {
			// params: ::: 后的哪一行的内容, 当:::为结束时 params 为空
			console.log('==========:', params)
			return params.trim().match(/^demo\s*(.*)$/)
		},
		render(tokens, idx) {
			const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/)
			if (tokens[idx].nesting === 1) {
				//  判断是否是开始标签
				const description = m && m.length > 1 ? m[1] : ''
                // 下一个类型是否是fence (代码块)
				const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : ''
				return `<demo-block>
        ${description ? `<div>${md.render(description)}</div>` : ''}
        <!--element-demo: ${content}:element-demo-->
        `
			}
			return '</demo-block>'
		},
	})

	md.use(mdContainer, 'tip')
	md.use(mdContainer, 'warning')
}

  1. fence处理 处理成 <template slot="highlight">xxx</template>以方便放到demo-block中

生成最终的vue文件

上面的步骤中已经将代码段的描述(放到了div中), 代码内容(放到了 :::demo 结果中的<!--element-demo:xxx:element-demo--> 中,代码重新进行了fence. 剩下的问题是处理源码,把源码转换成内部组件

将一段代码转换成组件源码

``html

step1 : 提取template 和 script
step2 : 将template 转换成render

```js
const finalOptions = {
    source: `<div>${template}</div>`,
    filename: 'inline-component', // TODO:这里有待调整
    compiler
  };
  const compiled = compileTemplate(finalOptions);

compiled.code 是个string 包含以下内容

// compiled.code
var render = function() {
  var _vm = this
  var _h = _vm.$createElement
  var _c = _vm._self._c || _h
  return _vm._m(0)
}
var staticRenderFns = [
  // ....
]
render._withStripped = truef

最终生成的组件代码是:

{
	render:function.
    staticRenderFns,//静态渲染函数
    ====script中的内容====
    methods: {
      hello() {
        alert('Hello World!');
      }
    }
    ========
}
  
> 最终生成的
```vue
 <template>
      <section class="content element-doc">
        ${output.join('')}
        <template slot="source"><element-demo1 /></template>
        <template slot="highlight"><pre v-pre> ....
      </section>
    </template>
    <script>
      export default {
        name: 'component-doc',
        components: {
          ${componentsString}
          element-demo1:{
          	render,
            staticRenderFns ...
          }
        }
      }
    </script>

问题

为什么非要转换成render 直接这样可以吗?

 element-demo1:{
                template:"...template中的code..",
                ....script中的code....
            }
  

原因

这个外部变量无法处理,这个变量属于组件的私有变量,但在组件眼里又是外部

解决办法==>闭包

const { stripScript, stripTemplate, genInlineComponentText } = require('./util')
const md = require('./config')
// source : 文件内容
module.exports = function(source, map, meta) {
   // console.log('===resourcePath:\n', this.resourcePath)
   // console.trace()
   const content = md.render(source)

   const startTag = '<!--element-demo:'
   const startTagLen = startTag.length
   const endTag = ':element-demo-->'
   const endTagLen = endTag.length

   let componenetsString = ''
   let id = 0 // demo 的 id
   let output = [] // 输出的内容
   let start = 0 // 字符串开始位置

   let privateTemplates = []

   let commentStart = content.indexOf(startTag)
   let commentEnd = content.indexOf(endTag, commentStart + startTagLen)
   while (commentStart !== -1 && commentEnd !== -1) {
   	output.push(content.slice(start, commentStart))

   	const commentContent = content.slice(commentStart + startTagLen, commentEnd)
   	const html = stripTemplate(commentContent)
   	let script = stripScript(commentContent)
   	// let demoComponentContent = genInlineComponentText(html, script)
   	const demoComponentName = `element-demo${id}`
   	output.push(`<template slot="source"><${demoComponentName} /></template>`)
   	var iHtml = html.replace(/^<template>\s*/, '')
   	iHtml = iHtml.replace(/<\/template>$/, '')
   	privateTemplates.push(`<template id="${demoComponentName}"><div>${iHtml}</div></template>`)

   	// if (script) {
   	// 	script = script.replace(/export\s+default\s*\{\s*/, '')
   	// 	script = script.replace(/\s*\};?\s*$/, '')
   	// } else {
   	// 	script = ''
   	// }
   	let result = script.match(/([\s\S]*)(export\s+default)\s*{([\s\S]+)(\};?)$/)
   	let preCode = result && result[1] ? result[1] : ''
   	let mainCode = result && result[3] ? result[3] : ''
   	let componentCode = `(function() { ${preCode} return {
   	  template:'#${demoComponentName}',${mainCode}
   	} })()`
   	// console.log('=====script======', script)
   	// componenetsString += `${JSON.stringify(demoComponentName)}: ${demoComponentContent},`
   	componenetsString += `${JSON.stringify(demoComponentName)}: ${componentCode},`

   	// 重新计算下一次的位置
   	id++
   	start = commentEnd + endTagLen
   	commentStart = content.indexOf(startTag, start)
   	commentEnd = content.indexOf(endTag, commentStart + startTagLen)
   }

   // 仅允许在 demo 不存在时,才可以在 Markdown 中写 script 标签
   // todo: 优化这段逻辑
   let pageScript = ''
   if (componenetsString) {
   	pageScript = `<script>
     export default {
       name: 'component-doc',
       components: {
         ${componenetsString}
       }
     }
   </script>`
   } else if (content.indexOf('<script>') === 0) {
   	// 硬编码,有待改善
   	start = content.indexOf('</script>') + '</script>'.length
   	pageScript = content.slice(0, start)
   }

   output.push(content.slice(start))
   let res = `
   <template>
     <section class="content element-doc">
       ${output.join('')}
     </section>
   </template>
   ${privateTemplates.join('')}
   ${pageScript}
 `
   if (privateTemplates.length) {
   	//
   }
   // console.log('===========\n', res)

   return res
}

还是失败了

没办法了