久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

深入wepy源碼:wpy文件編譯過程

 太極混元天尊 2018-05-20

本文摘要

來自摩拜前端團隊 yingye

本文從源碼入手分析了 wpy 文件的編譯過程,,在文末還介紹了如何編寫wepy plugin,。

歡迎關(guān)注本系列,留言并分享 小程序開發(fā) 中的體會,。


wepy 是騰訊開源的一款小程序框架,,主要通過預(yù)編譯的手段,讓開發(fā)者采用類 Vue 風(fēng)格開發(fā),。 讓我們一起看看,, wepy 是如何實現(xiàn)預(yù)編譯的。先放上一張官網(wǎng)的流程圖,,后面的分析可以參考該圖,。

wepy-cli 主要負(fù)責(zé) .wpy 文件的編譯,目錄結(jié)構(gòu)如下:

    

編譯的入口是 src/compile.js 中的 compile() 方法,,該方法主要是根據(jù)文件類型,,執(zhí)行不同的 compiler ,,比如 .wpy 文件會執(zhí)行 compile-wpy.js 下的 compile() 方法,。

  1. compile(opath) {

  2.  ...

  3.  switch(opath.ext) {  

  4.    case ext:  

  5.      cWpy.compile(opath);  

  6.      break;  

  7.    case '.less':  

  8.      cStyle.compile('less', opath);  

  9.      break;  

  10.    case '.sass':  

  11.      cStyle.compile('sass', opath);  

  12.      break;  

  13.    case '.scss':  

  14.      cStyle.compile('scss', opath);  

  15.      break;  

  16.    case '.js':  

  17.      cScript.compile('babel', null, 'js', opath);  

  18.      break;  

  19.    case '.ts':  

  20.      cScript.compile('typescript', null, 'ts', opath);  

  21.      break;  

  22.    default:  

  23.      util.output('拷貝', path.join(opath.dir, opath.base));

  24.    ...

  25.  }

  26. }  

.wpy文件拆解

compile-wpy.js 下的 compile() 方法,,核心調(diào)用了 resolveWpy() 方法。

resolveWpy() 方法,,主要是將 .wpy 拆解成 rst 對象,,并對其中的 template、script 做一些預(yù)處理,,然后將 template,、 script、 style 三部分移交給不同的 compiler 處理,。

生成rst對象

通過 xmldom 獲取 xml 對象,,然后遍歷節(jié)點,拆解為 rst對象,。

  1. import {DOMParser} from 'xmldom';

  2. export default {

  3.  createParser (opath) {

  4.    return new DOMParser({

  5.      ...

  6.    })

  7.  },

  8.  ...

  9.  resolveWpy () {

  10.    let xml = this.createParser(opath).parseFromString(content);

  11.  }

  12. }

rst對象結(jié)構(gòu)如下:

  1. let rst = {

  2.  moduleId: moduleId,

  3.  style: [],

  4.  template: {

  5.    code: '',

  6.    src: '',

  7.    type: ''

  8.  },

  9.  script: {

  10.    code: '',

  11.    src: '',

  12.    type: ''

  13.  }

  14. };

此外,,還對 template 做了如下一些預(yù)處理:

  • 獲取文件中的 import ,放入 rst.template.components 中

  • 獲取 props 和 events ,,放入 rst.script.code 中

compile-template

compile-template.js 中的 compile() 方法,,根據(jù) template 的 lang 值,執(zhí)行不同的 compiler ,,比如 wepy-compile-typescript ,。編譯完成后,執(zhí)行 compileXML 方法,,做了如下的操作:

  • updateSlot 方法: 替換 slot 內(nèi)容

  • updateBind 方法: 在 {{}} 和 attr 上加入組件的前綴,,例如: {{width}} -> {{$ComponentName$width}}

  • 把自定義的標(biāo)簽、指令轉(zhuǎn)換為 wxml 語法,,例如:

  1. <> for='xxx' index='idx' item='xxx' key='xxx'>

  2. <> wx:for='xxx' wx:for-index='xxx' wx:for-item='xxx' wx:key='xxxx'>

compile-style

依舊先是根據(jù) lang 值,,先執(zhí)行不同的 compiler ,比如 wepy-compile-less ,。編譯完成后,,執(zhí)行 src/style-compiler/scope.js 中的 scopedHandler() 方法,處理 scoped ,。

  1. import postcss from 'postcss';

  2. import scopeId from './scope-id';

  3. export default function scopedHandler (id, content) {

  4.  console.log('id is: ', id)

  5.  console.log('css content is: ', content)

  6.  return postcss([scopeId(id)])

  7.    .process(content)

  8.    .then(function (result) {

  9.      console.log('css result is: ', result.css)

  10.      return result.css

  11.    }).catch((e) => {

  12.      return Promise.reject(e)

  13.    })

  14. }

這里主要是利用 add-id 的 postcss 插件,,插件源碼可參考 src/style-compiler/scope-id.js。根據(jù)上面的代碼,,打印出來的log如下:

   

最后,,會把 requires 由絕對路徑替換為相對路徑,并在 wxss 中引入,,最終生成的 wxss 文件為:

  1. @import './../components/demo.wxss';

  2. Page{background:#F4F5F7} ...  

compile-script

依舊先是根據(jù) lang 值,,執(zhí)行不同的 compiler,。compiler 執(zhí)行完之后,判斷是否是 npm 包,,如果不是,,依據(jù)不同的 type 類型,加入 wepy 初始化的代碼,。

  1. if (type !== 'npm') {

  2.  if (type === 'page' || type === 'app') {

  3.    code = code.replace(/exports\.default\s*=\s*(\w+);/ig, function (m, defaultExport) {

  4.      if (defaultExport === 'undefined') {

  5.        return '';

  6.      }

  7.      if (type === 'page') {

  8.        let pagePath = path.join(path.relative(appPath.dir, opath.dir), opath.name).replace(/\\/ig, '/');

  9.        return `\nPage(require('wepy').default.$createPage(${defaultExport} , '${pagePath}'));\n`;

  10.      } else {

  11.        appPath = opath;

  12.        let appConfig = JSON.stringify(config.appConfig || {});

  13.        let appCode = `\nApp(require('wepy').default.$createApp(${defaultExport}, ${appConfig}));\n`;

  14.        if (config.cliLogs) {

  15.          appCode += 'require(\'./_wepylogs.js\')\n';

  16.        }

  17.        return appCode;

  18.      }

  19.    });

  20.  }

  21. }

接下來會執(zhí)行 resolveDeps() 方法,,主要是處理 requires。根據(jù) require 文件的類型,,拷貝至對應(yīng)的目錄,,再把 code 中的 require 代碼替換為 相對路徑。

處理好的 code 最終會寫入 js 文件中,,文件存儲路徑會判斷類型是否為 npm,。

  1. let target;

  2. if (type !== 'npm') {

  3.  target = util.getDistPath(opath, 'js');

  4. } else {

  5.  code = this.npmHack(opath, code);

  6.  target = path.join(npmPath, path.relative(opath.npm.modulePath, path.join(opath.dir, opath.base)));

  7. }

plugin

根據(jù)上面的流程圖,可以看出所有的文件生成之前都會經(jīng)過 Plugin 處理,。先來看一下,,compiler 中是如何載入 Plugin 的。

  1. let plg = new loader.PluginHelper(config.plugins, {

  2.  type: 'css',

  3.  code: allContent,

  4.  file: target,

  5.  output (p) {

  6.    util.output(p.action, p.file);

  7.  },

  8.  done (rst) {

  9.    util.output('寫入', rst.file);

  10.    util.writeFile(target, rst.code);

  11.  }

  12. });

其中,,config.plugins 就是在 wepy.config.js 中定義的 plugins,。讓我們來看一下 PluginHelper 類是如何定義的。

  1. class PluginHelper {

  2.  constructor (plugins, op) {

  3.    this.applyPlugin(0, op);

  4.    return true;

  5.  }

  6.  applyPlugin (index, op) {

  7.    let plg = loadedPlugins[index];

  8.    if (!plg) {

  9.      op.done && op.done(op);

  10.    } else {

  11.      op.next = () => {

  12.        this.applyPlugin(index + 1, op);

  13.      };

  14.      op.catch = () => {

  15.        op.error && op.error(op);

  16.      };

  17.      if (plg)

  18.        plg.apply(op);

  19.    }

  20.  }

  21. }

在有多個插件的時候,,不斷的調(diào)用 next(),,最后執(zhí)行 done()

編寫plugin

wxss 與 css 相比,,拓展了尺寸單位,,即引入了 rpx 單位。但是設(shè)計童鞋給到的設(shè)計稿單位一般為 px,,那現(xiàn)在我們就一起來編寫一個可以將 px 轉(zhuǎn)換為 rpx 的 wepy plugin,。

從 PluginHelper 類的定義可以看出,是調(diào)用了 plugin 中的 apply() 方法,。另外,,只有 .wxss 中的 rpx 才需要轉(zhuǎn)換,所以會加一層判斷,,如果不是 wxss 文件,,接著執(zhí)行下一個 plugin。 rpx 轉(zhuǎn)換為 px 的核心是,,使用了 postcss-px2units plugin,。下面就是設(shè)計好的 wepy-plugin-px2units,更多源碼可參考 github 地址( https://github.com/yingye/wepy-plugin-px2units ),。

  1. import postcss from 'postcss';

  2. import px2units from 'postcss-px2units';

  3. export default class {

  4.  constructor(c = {}) {

  5.    const def = {

  6.      filter: new RegExp('\.(wxss)$'),

  7.      config: {}

  8.    };

  9.    this.setting = Object.assign({}, def, c);

  10.  }

  11.  apply (op) {

  12.    let setting = this.setting;

  13.    if (!setting.filter.test(op.file)) {

  14.      op.next();

  15.    } else {

  16.      op.output && op.output({

  17.        action: '變更',

  18.        file: op.file

  19.      });

  20.      let prefixer = postcss([ px2units(this.setting.config) ]);

  21.      prefixer.process(op.code, { from: op.file }).then((result) => {

  22.        op.code = result.css;

  23.        op.next();

  24.      }).catch(e => {

  25.        op.err = e;

  26.        op.catch();

  27.      });

  28.    }

  29.  }

  30. }

最后

本文分析的源碼以 [email protected] 版本為準(zhǔn),,更多信息可參考 wepy github (即 github 1.7.x 分支,,https://github.com/Tencent/wepy/tree/1.7.x )。另外,,文中有任何表述不清或不當(dāng)?shù)牡胤?,歡迎大家批評指正。



    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多