究竟什麼是前端腳手架?

😔 咱也不知道咱也不敢問啊javascript

先查查百度百科裏對「腳手架」的定義吧:css

腳手架是爲了保證各施工過程順利進行而搭設的工做平臺。

而後搜一下「腳手架」,基本上都是如下幾類:html

  • Vue/React 腳手架
  • 使用 Node、yeoman 打造本身的腳手架
  • 從零搭建 webpack 腳手架

此時仍是沒法肯定什麼是「腳手架」,也許我心目中的腳手架應該是 vue/cli 或者 create-react-app 吧,而後我打開他們的文檔,可是他們的介紹上並無說這是一款腳手架...前端

談一下我本身的「腳手架」

😔 我最怕別人看到個人「腳手架」後說這有什麼卵用...vue

看了一下我第一次在 Github 上的提交記錄 Commits on Feb 13, 2017,我入行三年多,那時應該是我第一次進入前端工程化的時候吧。在此以前我在公司接手的都是一些很簡單的項目,直接新建文件夾,隨手下載一個jQuery,而後新建 index.html main.js style.css,有沒有一樣經歷的小夥伴們?java

後來作的項目多了,以爲每次這麼新建項目太麻煩,我新建了一個文件夾,專門存放初始的模板,而後複製粘貼,繼續擼。node

再後來,接觸到 vue,他能夠實如今終端內輸入一行指令就能生成模板,這可比我複製粘貼看起來高端多了,爲了裝逼我開始了研究如何開發本身的「腳手架」。react

當時還真是沒有幾篇文章把這種操做說的很明白,甚至我並不知道我要作的東西叫什麼(腳手架)。webpack

我理解的「腳手架」

🤓 百科裏說的很對個人思路,首要的就是保證個人項目能夠順利進行。ios

  • 可以快速幫我生成新項目的目錄模板(Node.js)。
  • 可以提高個人開發效率和開發的溫馨性(webpack)。

分享點乾貨

從零搭建這種我就不說了,畢竟一搜一堆,基本上就是推薦幾個庫,例如 commander、inquirer、ora 等等。分享一些在個人腳手架開發時遇到的一些問題和需求,分享想給你們。

版本驗證

首先推薦工具庫:

semver,版本對比。

request,發送請求,固然你也能夠用 axios。

const semver = require('semver');
const request = require('request');
  • Node.js 版本驗證

若是你的腳手架想分享給別人用,這步最好不要避免,由於若是你用了一些現代化的 ES 語法,好比說 async await,老版本跑不起來的。

function checkNodeVersion (wanted) {
  // process.version 能夠獲取當前的 node 版本
  if (!semver.satisfies(process.version, wanted)) {
    console.log('Node版本不支持巴拉巴拉');
    // 退出進程
    process.exit(1);
  }
}
  • 腳手架版本驗證

正如上面所說,你若是分享給別人用,在你修改了一些 bug 後,但願其餘人用最新的版本,那就應該提示他。

function checkPackageVersion(url) {
  return new Promise((resolve, reject) => {
    request(url, function (error, response, body) {
      if (!error && response.statusCode === 200){
        let version = JSON.parse(body).version;
        if (semver.lte(version, requiredVersion)) {
          resolve();
        } else {
          console.log('須要更新你的包巴拉巴拉');
          process.exit(1);
        }
      } else {
        console.log('發送請求失敗巴拉巴拉');
        resolve();
      }
    });
  });
}

參數 url 固然傳入 npm 的連接 https://registry.npmjs.org/[你的包名]/latest

當前路徑下是否存在相同的文件夾

若是不作這層判斷,你新生成的項目極可能會覆蓋你已有的項目,別問我爲啥想到這麼作 😭

function hasFolder(name) {
  return new Promise (resolve => {
    fs.exists(name, exists => {
      if (exists) {
        console.log('已經存在相同目錄巴拉巴拉');
        process.exit(1);
      } else {
        resolve();
      }
    });
  });
};

這裏加了一層 Promise 是由於 Node 去檢測是否存在文件夾是個異步操做,也須要耗時,這麼作比較保險。

清空控制檯

當你輸入完命令後,好像進入了新的頁面同樣,看起來很舒服。

function clearConsole(color, str) {
  if (process.stdout.isTTY && store.cmd !== 'test') {
    const blank = '\n'.repeat(process.stdout.rows);
    console.log(blank);
    readline.cursorTo(process.stdout, 0, 0);
    readline.clearScreenDown(process.stdout);
  }
}

拷貝模板

不少關於若是構建腳手架裏提到一個工具 download-git-repo,在 github 或其餘倉庫中下載模板。我並非很喜歡這種操做,一、耗時,讓腳手架構建速度更慢了,在沒有網絡的狀況下沒法構建。二、在 git 倉庫中還須要新建項目模板,感受把一個項目分離成了兩個,不方便管理。

因此我打算直接從全局目錄下將模板文件夾拷貝到當前路徑下:

使用一個工具 fs-extra,node.js 新手最好不要試圖用原生接口拷貝一個文件夾。

const src = path.resolve(__dirname, '../template');

const dest = path.resolve(process.cwd(), store.dirname);

兩個概念:

全局環境路徑:

const src = path.resolve(__dirname, '你的模板文件夾相對路徑')

當前環境路徑:

const dest = path.resolve(process.cwd(), '你建立項目的名稱');
fs.copy(src, dest).then(() => /* 巴拉巴拉 */);

自動選擇包管理器

如今用 yarn 的人愈來愈多,並且確實效率很高,若是安裝過 yarn 就讓它做爲默認包管理器去自動安裝依賴吧。

function packageManagement() {
  try {
    child_process.execSync('yarnpkg --version', { stdio: 'ignore' });
    return 'yarn';
  } catch (e) {
    return 'npm';
  }
}

自動安裝依賴

這裏用到 Node.js 中的 child_process.spawn 方法

這裏舉個例子,想要執行 npm install webpack -D

const ls = spawn('npm', ['isntall', 'webpack', '-D'], {shell: true});
ls.on('close', (code) => /* 巴拉巴拉 */)
  • 第一個參數:要運行的命令。
  • 第二個參數:數組,字符串參數的列表。
  • 第三個參數:配置,這裏把 shell 設置爲 true。
  • 使用 on 方法監聽執行結果。
這裏推薦安裝的包帶有版本號,若是直接安裝會安裝最新版,可能會致使不兼容。

提一個 webpack 的插件

ProgressPlugin,用於監聽編譯進度。

plugins: [
  new webpack.ProgressPlugin(function(percentage) {
    // percentage 進度 0-1
  })
]

這裏配合前面說到的清空控制檯,能夠實現更好的體驗。

使用 IP 訪問項目

這裏指的是經過 webpack 啓動的 devServer。

host 配置爲 0.0.0.0

經過下面的函數獲取到本機的 IP 地址,這樣就能夠在同網下使用移動設備作測試了。

function getIPAdress() {
  let interfaces = require('os').networkInterfaces();
  // eslint-disable-next-line guard-for-in
  for (let devName in interfaces) {
    let iface = interfaces[devName];
    for (let i = 0; i < iface.length; i++) {
      let alias = iface[i];
      if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
        return alias.address;
      }
    }
  }
}

再逼逼幾句

這是我理解中的「腳手架」,但願其餘小夥伴也評論一下本身理解的腳手架。

😢 已經近一年沒有作過技術分享了,天天在掘金裏潛水,偶爾發點沸點,不敢在首頁發內容,總以爲本身技術不足,怕大佬噴,自尊心受到創傷。

最後分享一下個人「腳手架」,這個項目在我面試中也起到了不錯的效果:

文檔:https://codexu.github.io/

相關文章
相關標籤/搜索