Element源码系列——buildfile命令

Element源码系列——build:file命令

build:file是一个组合命令,它由四个子命令构成.命令大致都是通过解析配置文件,生成最终文件.

那么下面,让我们来一个一个具体的看看每个命令是做什么的.

1.icon图标初始化 node build/bin/iconInit.js

该子命令的作用是读取icon的样式表,通过解析样式表.最终生成一份所有可用的icon清单

它承接了样式表与官方文档icon介绍之间的关系,也是说当我们在样式表中添加新的字体图标时,只需重新编译文件后打包网站代码就可以实现更新

(1).首先通过fs.readFileSync读取’../../packages/theme-chalk/src/’下的icon.scss文件,所有已经编写好的字体icon样式代码都在该文件中。

var fontFile = fs.readFileSync(path.resolve(__dirname, '../../packages/theme-chalk/src/icon.scss'), 'utf8');

// icon.scss文件部分代码
// .el-icon-info:before { content: "\e61a"; } "\e61a"为注册的字体
// .el-icon-error:before { content: "\e62c"; }

(2).通过postcss解析后样式表后,通过正则捕获el-icon-(xxx):before中的内容,并存入数组中

var nodes = postcss.parse(fontFile).nodes;
var classList = [];
var reg = new RegExp(/\.el-icon-([^:]+):before/);
var arr = selector.match(reg);

if (arr && arr[1]) {
    classList.push(arr[1]); //arr[1]为第一个捕获组
}

(3).生成’../../examples/icon.json’ 文件

fs.writeFile(path.resolve(__dirname, '../../examples/icon.json'), JSON.stringify(classList), () => {});

// icon.json文件格式如下
// ["info","error","success","warning",......]

(4).在’../../examples/docs/icon.md’中调用icon.json文件,生成网页文档

</script>
var iconList = require('examples/icon.json');
export default {
  data() {
    return {
      icons: iconList //获取json文件中的数组
    };
  }
}
<script>
<ul class="icon-list">
  <li v-for="name in icons" :key="name"> //遍历数组数据生成所有已配置的icon
    <span>
      <i :class="'el-icon-' + name"></i>
      <span class="icon-name">{{'el-icon-' + name}}</span>
    </span>
  </li>
</ul>

2.编译入口文件 node build/bin/build.entry.js

我们在开发时,为了考虑分工以及效率等因素,开发的源码肯定是分模块分包的.但是考虑到别人使用方便,一次引入的版本肯定是必须的,再不济也要为webpack考虑下.所以,每次打包前都要修改入口文件的代码肯定是不可取的.这个命令就是为了解决入口文件的问题,他会通过解析json文件,并使用字符串模板生成一个入口文件.

(1).编写字符串模板

// 入口文件导出路径
var OUTPUT_PATH = path.join(__dirname, '../../src/index.js');
// import文件模板
var IMPORT_TEMPLATE = 'import {{name}} from \'../packages/{{package}}/index.js\';';
// 安装组件名称模板
var INSTALL_COMPONENT_TEMPLATE = '  {{name}}';
// 主模板中{{ inclue }},{{ install }},{{ version }},{{ list }}为需要替换的模板语法
// {{ include }} 需要替换为 import Row from '../packages/row/index.js';
// {{ install }} 是为需要安装的组件
// {{ version }} 是当前版本号
// {{ list }} 是最终导出的模块
var MAIN_TEMPLATE = `/* Automatically generated by './build/bin/build-entry.js' */
{{include}} 
import locale from 'element-ui/src/locale';
import CollapseTransition from 'element-ui/src/transitions/collapse-transition';

const components = [
{{install}},
  CollapseTransition
];

。。。

module.exports = {
  version: '{{version}}',
  locale: locale.use,
  i18n: locale.i18n,
  install,
  CollapseTransition,
  Loading,
{{list}}
};`;

(2).通过json-templater 插件对模板进行编译

// render函数会将第二个参数中的key,与{{ mustache }}语法模板中的变量一一对应,最终以value值对其替换
var render = require('json-templater/string'); 
// EOL是当前系统下的行尾符的常量。windows下为'\r\n'
var endOfLine = require('os').EOL;
// render模板
var template = render(MAIN_TEMPLATE, {
  // import语法字符串,通过endOfLine进行换行
  include: includeComponentTemplate.join(endOfLine),
  // Vue安装组件字符串,通过,加上endOfLine进行分割
  install: installTemplate.join(',' + endOfLine),
  // 获取版本信息
  version: process.env.VERSION || require('../../package.json').version,
  // 导出模块,通过,加上endOfLine进行分割
  list: listTemplate.join(',' + endOfLine)
});

(3).写入文件

var OUTPUT_PATH = path.join(__dirname, '../../src/index.js');
fs.writeFileSync(OUTPUT_PATH, template); // 写入文件

// 最终生成的入口文件index.js
import Pagination from '../packages/pagination/index.js';
import Dialog from '../packages/dialog/index.js';
...

const components = [
  Pagination,
  Dialog,
  Autocomplete,
  ...
]
module.exports = {
  version: '2.3.6',
  locale: locale.use,
  i18n: locale.i18n,
  install,
  CollapseTransition,
  Loading,
  Pagination,
  Dialog,
  ...
}
...

3.node build/bin/i18n.js

国际化用老土点的话说就是一套网页模板,里面的内容语言不同,选择不同的语言内容而已.而这个命令就是干这个事情的

(1).获取page.json文件,文件中主要存放了按照约定编写的三套网页内容

// 获取json文件
var langConfig = require('../../examples/i18n/page.json');

page.json文件格式如下,可以看到数据一个数组.每个数组存放了一种语言.pages字段下所代表的的是不同的页面.

而1,2,3等序号就是我们需要根据不同语言所替换模板中的内容.

[
  {
    "lang": "zh-CN",
    "pages": {
      "index": {
        "1": "网站快速成型工具",
        "2": "Element,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库",
        "3": "指南",
        "4": "了解设计指南,帮助产品设计人员搭建逻辑清晰、结构合理且高效易用的产品。",
        "5": "查看详情",
        "6": "组件",
        "7": "使用组件 Demo 快速体验交互细节;使用前端框架封装的代码帮助工程师快速开发。",
        "8": "资源",
        "9": "下载相关资源,用其快速搭建页面原型或高保真视觉稿,提升产品设计效率。",
        "lang": "zh-CN",
        "titleSize": "34",
        "paraSize": "18"
      },
      "component": {},
      "changelog": {
        "1": "更新日志",
        "2": "zh-CN"
      },
      "design": {
        "1": "设计原则",
        "2": "一致",
        ...
      }
     ...
    }
  ...
},
    ...
]

(2).遍历文件,生成文件

在了解json格式

langConfig.forEach(lang => {
  try {
    // 判断目录是否存在
    fs.statSync(path.resolve(__dirname, `../../examples/pages/${ lang.lang }`));
  } catch (e) {
    // 新建文件夹
    fs.mkdirSync(path.resolve(__dirname, `../../examples/pages/${ lang.lang }`));
  }
  // 第二重循环
  Object.keys(lang.pages).forEach(page => {
    // 获取模板路径
    var templatePath = path.resolve(__dirname, `../../examples/pages/template/${ page }.tpl`);
    // 定义输出路径
    var outputPath = path.resolve(__dirname, `../../examples/pages/${ lang.lang }/${ page }.vue`);
    // 读取模板
    var content = fs.readFileSync(templatePath, 'utf8');
    // 获取内容对象
    var pairs = lang.pages[page];
    // 第三重循环
    Object.keys(pairs).forEach(key => {
      // 将内容,按照键进行替换
      content = content.replace(new RegExp(`<%=\\s*${ key }\\s*>`, 'g'), pairs[key]);
    });
    // 重新写入文件
    fs.writeFileSync(outputPath, content);
  });
});

4.编译版本信息 node build/bin/version.js

该命令主要作用取package.json或者配置环境信息中的版本号,生成version.json,并通过Vue组件读取json文件生成示例页面

var fs = require('fs');
var path = require('path');
// 获取版本信息
var version = process.env.VERSION || require('../../package.json').version;
// 重要版本列表
var content = { '1.4.13': '1.4', '2.0.11': '2.0', '2.1.0': '2.1', '2.2.2': '2.2', '2.3.9': '2.3' };
// 添加当前版本信息
if (!content[version]) content[version] = '2.4';
// 写入文件
fs.writeFileSync(path.resolve(__dirname, 
                              '../../examples/versions.json'), JSON.stringify(content));

// versions.json
{"1.4.13":"1.4","2.0.11":"2.0","2.1.0":"2.1","2.2.2":"2.2","2.3.9":"2.3","2.4.3":"2.4"}

// 调用文件../examples/components/header.vue
created() {
    const xhr = new XMLHttpRequest();
    xhr.onreadystatechange = _ => {
        if (xhr.readyState === 4 && xhr.status === 200) {
            const versions = JSON.parse(xhr.responseText);
            //复制对象
            this.versions = Object.keys(versions).reduce((prev, next) => {
                prev[next] = versions[next];
                return prev;
            }, {});
        }
    };
    xhr.open('GET', '/versions.json'); //请求json数据
    xhr.send();
}

总结

感谢阅读!

感觉element团队的贡献!

如需跳转,请点Element源码系列——搭建开发环境

猜你喜欢

转载自blog.csdn.net/m0_37972557/article/details/81089860