<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          帶你揭開自動化構(gòu)建的神秘面紗

          共 12899字,需瀏覽 26分鐘

           ·

          2021-03-06 01:45

          c4b9a78d3b06a4879600b4b4362e7be5.webp



          前端獵手
          ?鏈接每一位開發(fā)者,讓編程更有趣兒!關(guān)注


          前言:對于我們這些日常基于腳手架項目開發(fā),使用yarn/npm run start、yarn/npm run build等命令完成自動化構(gòu)建的開發(fā)者來說,重要的自動化構(gòu)建仿佛變成了前端的一個黑盒知識。但是,掌握前端工程的自動化構(gòu)建,是學(xué)習(xí)前端工程化以及進階高級前端所必不可缺少的部分。

          通過這篇文章,我嘗試把我自己對自動化構(gòu)建知識體系的系統(tǒng)化認(rèn)識托盤而出,希望能夠?qū)﹂w下有所幫助。同樣,我更喜歡的是您能批判我的一些觀點或者指出我的一些問題,因為忠言逆耳利于行。

          注意:文章的側(cè)重點是對自動化構(gòu)建知識的系統(tǒng)化探討,不會是對某一個具體工具使用上的面面俱到,畢竟那是官方文檔該做的事情。

          對于自動化構(gòu)建知識體系的系統(tǒng)化認(rèn)識,從個人認(rèn)識出發(fā),我用腦圖做了以下整理:

          04aa19d20d7b5029c93898c904f21490.webp

          接下來的行文,我都會圍繞這副腦圖展開,如果您有興趣繼續(xù)往下看下去,我希望您能在這幅圖上停留多一些時間。

          好地,按照上述腦圖中的邏輯,接下來我會分成以下幾個部分來展開探討本文。

          • 理解前端工程的自動化構(gòu)建
          • 實現(xiàn)前端工程的自動化構(gòu)建:npm script方式
          • 實現(xiàn)前端工程的自動化構(gòu)建:gulp方式
          • 其它方式實現(xiàn)前端工程的自動化構(gòu)建

          好的,理清楚行文思路之后,進入第一點,理解前端工程的自動化構(gòu)建。

          一:理解前端工程的自動化構(gòu)建

          1.先理解一下為什么會出現(xiàn)這玩意

          簡單來說,隨著前端需求和項目的日益復(fù)雜,出于提高開發(fā)效率、用戶體驗以及其它工程上的需要,我們通常會借助很多更高階的語法(如es6、ts、less等)或者服務(wù)(如web server)等來幫助我們更快更好的開發(fā)、調(diào)試、增強一個前端工程。但是,這會導(dǎo)致一個問題,就是我們寫的代碼會離瀏覽器或node可解析運行的代碼越來越遠。

          為了解決這個問題,前端工程構(gòu)建的概念就逐漸豐富完整了起來。也就是說,前端工程構(gòu)建就是指前端項目從源代碼到一個能按需運行(開發(fā)環(huán)境、生產(chǎn)環(huán)境)的前端工程所需要做的所有事情。由于前端工程的構(gòu)建過程中會包含很多任務(wù)并且工程需要頻繁構(gòu)建,所以按照任何簡單機械的重復(fù)勞動都應(yīng)該讓機器去完成的思想,我們應(yīng)該自動化去完成工程的構(gòu)建,提高構(gòu)建效率

          2.從這玩意的具體實踐角度來再理解一次

          前面提到了前端工程自動化構(gòu)建的本質(zhì),但是這個理解離我們具體實踐它還是有點遠,下面再說說我對自動化構(gòu)建實踐上的理解吧。

          我認(rèn)為,前端工程構(gòu)建的具體實踐形式就是一個任務(wù)流,完成了這個任務(wù)流中的所有任務(wù)即完成了前端工程構(gòu)建。而自動化構(gòu)建,也就是不用手動的執(zhí)行這個任務(wù)流中的一個個任務(wù)。

          好的,經(jīng)過上面兩點講解,我覺得我已經(jīng)把我對它的所有理解都已經(jīng)傾囊相授了。

          為了引導(dǎo)接下來對自動化構(gòu)建具體實現(xiàn)的講解,下面我們再從自動化構(gòu)建就是完成一個任務(wù)流這個實踐角度理解來展開細(xì)致探討,也就是以下這兩點,即:

          • 理解構(gòu)建任務(wù)流中的任務(wù)
          • 理解構(gòu)建任務(wù)流

          3.理解構(gòu)建任務(wù)流中的任務(wù)

          對比于JavaScript的函數(shù),個人對任務(wù)是這么分類的:

          • 單任務(wù):同步任務(wù)和異步任務(wù)
          • 多任務(wù):并行任務(wù)、串行任務(wù)

          同步任務(wù)和異步任務(wù)無須解釋,這里說說并行任務(wù)和串行任務(wù)。任務(wù)并行可以用于縮短多個任務(wù)的執(zhí)行時間。因為node是單線程執(zhí)行的,我認(rèn)為它并不能縮短多個同步任務(wù)并行的執(zhí)行時間,但是構(gòu)建過程中的任務(wù)通常都會涉及到IO流,所以大部分任務(wù)都是異步任務(wù),IO任務(wù)并行可以避免IO阻塞線程執(zhí)行,進而縮短多個任務(wù)的執(zhí)行時間。

          而任務(wù)串行可以保證任務(wù)之間的有序執(zhí)行,比如在開發(fā)環(huán)境下,我們肯定要先執(zhí)行編譯任務(wù),然后才能執(zhí)行啟動開發(fā)服務(wù)器的任務(wù)。

          理解了構(gòu)建過程中的任務(wù)之后,下面再列舉一些日常開發(fā)的構(gòu)建過程中,我們所常見到的任務(wù)。

          前端構(gòu)建過程中的常見任務(wù)

          任務(wù)名任務(wù)職責(zé)
          Eslint檢查統(tǒng)一代碼風(fēng)格
          babel轉(zhuǎn)換ES6 -> ES5
          typescript轉(zhuǎn)換Ts -> Js
          sass轉(zhuǎn)換sass -> css
          less轉(zhuǎn)換less -> css
          html、css、js壓縮.html -> .min.html、.css->.min.css、.js->.min.js
          web server開發(fā)服務(wù)器
          js、css兼容兼容不同瀏覽器
          ......

          除了上述表格中列舉的任務(wù)之外,在不同的項目不同的場景中還會有不同的構(gòu)建任務(wù),這里就不再一一贅述了。上面說到構(gòu)建其實就是完成一個任務(wù)流,在理解和認(rèn)識了常見任務(wù)之后,接下來我們理解一下前端工程當(dāng)中的任務(wù)流。

          4.理解構(gòu)建任務(wù)流

          任務(wù)流的理解可不只是多個任務(wù)這么簡單,任務(wù)流是要為目的服務(wù)的,就好比生產(chǎn)一個產(chǎn)品,必須完整跑完生產(chǎn)流水線一樣。所以我們這里得從構(gòu)建目的的角度來理解任務(wù)流。

          前端構(gòu)建是為前端工程服務(wù)的,而前端工程又是為用戶服務(wù)的。對應(yīng)于開發(fā)環(huán)境和生產(chǎn)環(huán)境,前端工程可以分為開發(fā)環(huán)境工程和生產(chǎn)環(huán)境工程,其中開發(fā)環(huán)境工程為開發(fā)者服務(wù),生產(chǎn)環(huán)境工程為用戶服務(wù)。

          滿足工程使用者的需求是我們構(gòu)建工程的終極目的,所以有必要投其所好,根據(jù)工程的使用者不同,完成他所需要的的一連串任務(wù),也就是任務(wù)流。這時可以根據(jù)構(gòu)建后工程的目標(biāo)使用者來劃分,把任務(wù)流分為開發(fā)環(huán)境構(gòu)建任務(wù)流和生產(chǎn)環(huán)境構(gòu)建任務(wù)流兩種。這兩點認(rèn)識很重要,所以我們把它兩單獨拎出來講解。

          我們先來理解一下開發(fā)環(huán)境的構(gòu)建任務(wù)流。

          5.理解開發(fā)環(huán)境的構(gòu)建任務(wù)流

          開發(fā)環(huán)境構(gòu)建任務(wù)流構(gòu)建后的工程是為開發(fā)者服務(wù)的。開發(fā)者需要開發(fā)調(diào)試代碼,所以開發(fā)環(huán)境任務(wù)流構(gòu)建的工程需要實現(xiàn)以下功能:

          功能項包含任務(wù)
          語法檢查Eslint
          語法轉(zhuǎn)換ES6 -> ES5、Sass -> less、Ts->Js等等
          模擬生產(chǎn)環(huán)境web開發(fā)服務(wù)器:devServer
          易于調(diào)試sourceMap
          ......

          開發(fā)者需要不斷修改代碼查看效果,所以除了滿足功能之外,還需要加快構(gòu)建速度并且自動刷新,以保證良好的使用體驗。

          優(yōu)化方式實現(xiàn)方案
          加快構(gòu)建速度devServer熱模塊替換
          自動刷新devServer 監(jiān)聽源代碼
          ......

          關(guān)于web開發(fā)服務(wù)器devServer

          使用web開發(fā)服務(wù)器可以模擬像使用nginx、tomcat等服務(wù)器軟件一樣的線上環(huán)境,它在功能以及配置上都與nginx以及tomcat類似, 最簡單的配置就是指明資源路徑baseUrl以及服務(wù)啟動ip和端口port即可。在開發(fā)環(huán)境啟動本地服務(wù)時,配置代理可以在符合同源策略的情況下解決跨域問題

          開發(fā)服務(wù)器除了可以模擬線上環(huán)境之外,更加強大的一點是它可以監(jiān)聽源代碼,實現(xiàn)熱部署和自動刷新功能

          好的,下面我們再來理解一下生產(chǎn)環(huán)境的構(gòu)建任務(wù)流。

          5.理解生產(chǎn)環(huán)境的構(gòu)建任務(wù)流

          生產(chǎn)環(huán)境構(gòu)建任務(wù)流構(gòu)建后的工程是為用戶服務(wù)的。與開發(fā)環(huán)境相比,它也需要語法檢查以及編譯功能,但不需要考慮修改以及調(diào)試代碼的問題,它關(guān)注的是瀏覽器兼容以及運行速度等問題。

          功能項包含任務(wù)
          語法檢查Eslint
          語法轉(zhuǎn)換ES6 -> ES5、Sass -> less、Ts->Js等等
          語法兼容不同瀏覽器的js、css語法兼容
          下載速度資源壓縮與合并
          ......

          生產(chǎn)環(huán)境的優(yōu)化除了資源的下載速度之外,還可以從很多方面入手,下面是其中的一些方面以及實現(xiàn)方案。

          優(yōu)化方面實現(xiàn)方式
          下載優(yōu)化treeshaking、代碼分割、懶加載
          運行優(yōu)化代碼上優(yōu)化性能
          離線訪問pwa技術(shù)
          ......

          終于把任務(wù)以及任務(wù)流淺顯粗陋的講完了,接下來我們先是使用npm scripts來實現(xiàn)簡單項目的自動化構(gòu)建,而后學(xué)習(xí)一下Gulp工具如何實現(xiàn)復(fù)雜項目的自動化構(gòu)建

          抱歉,文章那么長,讓你看累了、倦了。但你要知道,我他喵的寫文章更累啊,堅持一下,然后點個贊和關(guān)注吧( ̄▽ ̄)~■干杯□~( ̄▽ ̄)。

          二:實現(xiàn)前端工程的自動化構(gòu)建:npm script方式

          前面說到,完成前端工程構(gòu)建也就是完成任務(wù)流。任務(wù)流由任務(wù)組成,而任務(wù)又由腳本代碼實現(xiàn)。

          對于任務(wù)的調(diào)用,我們在定義好任務(wù)腳本或者安裝好所需的cli模塊之后,我們只需在package.json的scripts選項中配置一條script,就可以方便地調(diào)用任務(wù)腳本或者cli模塊。

          cli模塊提供了腳本命令,可以使用npm/npx/yarn運行該模塊所提供的腳本。

          這里不得不提一下node_modules/.bin文件夾,我們在項目中安裝的cli模塊都會有一個cmd文件出現(xiàn)在這里。當(dāng)我們在項目中需要調(diào)用這些cli模塊時,只需yarn/npx cli模塊名的方式就可以很方便的調(diào)用這些cli模塊。

          對于任務(wù)流的調(diào)用,我們則可以借助一些可以幫助任務(wù)組合(并行和串行)的庫,而后在npm script中配置一條組合任務(wù),調(diào)用它以啟動構(gòu)建任務(wù)流。

          好的,通過上面的分析之后,我們接下來展開講述一下npm scripts如何實現(xiàn)任務(wù)以及任務(wù)流的構(gòu)建。

          1.單任務(wù)注冊調(diào)用示例

          下面是sass轉(zhuǎn)換和ES6轉(zhuǎn)換的兩個單任務(wù)示例:

          • 注冊任務(wù):package.json中配置script
            "scripts": {
          "sass": "sass scss/main.scss css/style.css",
          "es6": "babel es6 --out-dir es5",
          },
          "devDependencies": {
          "@babel/cli": "^7.12.8",
          "@babel/core": "^7.12.9",
          "sass": "^1.29.0"
          }
          • 調(diào)用任務(wù):
          # sass轉(zhuǎn)換
          yarn sass
          # es6轉(zhuǎn)換
          yarn es6
          • 調(diào)用原理追溯

          最基本的腳本調(diào)用也就是用某個命令(如node)去執(zhí)行一個文件,這里直接使用yarn就可以觸發(fā)script中的任務(wù)難免會讓人有點疑惑。下面是我為您整理的任務(wù)調(diào)用追溯,理解它有時候能幫助你定位解決一些問題。

          • sass轉(zhuǎn)換任務(wù)追溯:yarn sass(觸發(fā)任務(wù)) -> sass scss/main.scss css/style.css -> node_modules/.bin/sass.cmd -> node_modules/sass/sass.js -> ...code

          • es6轉(zhuǎn)換任務(wù)追溯:yarn es6(觸發(fā)任務(wù)) -> babel es6 --out-dir es5 -> node_modules/.bin/babel.cmd -> node_modules/@babel\cli\bin\babel.js -> node_modules/@babel\cli\lib\index.js -> ...code

          2.簡單任務(wù)流構(gòu)建示例

          這里需要再重申一點,任務(wù)流不等同于任務(wù)組合,它與構(gòu)建目的有關(guān)。這里我們假設(shè)我們前端工程的構(gòu)建目的就只是sass轉(zhuǎn)換和es6轉(zhuǎn)換,那么我們以如下形式實現(xiàn)自動化構(gòu)建。

          • 注冊任務(wù):package.json中配置script

          注意:對于任務(wù)流中的任務(wù)組合我們這里通過npm-run-all這個庫來幫助我們實現(xiàn),這個庫提供了兩個cmd文件,nun-p.cmd實現(xiàn)任務(wù)的并行,nun-s.cmd實現(xiàn)任務(wù)的串行。

            "scripts": {
          "sass": "sass scss/main.scss css/style.css",
          "es6": "babel es6 --out-dir es5",
          "build": "run-p sass es6"
          },
          "devDependencies": {
          "npm-run-all": "^4.1.5",
          "@babel/cli": "^7.12.8",
          "@babel/core": "^7.12.9",
          "sass": "^1.29.0"
          }
          • 調(diào)用任務(wù):
          yarn build

          3.具體工程構(gòu)建示例

          下圖即是我們想要構(gòu)建的簡單前端項目:

          afc035f749542228889a238e9189c6d4.webp

          這個項目很簡單,它只包含一個html文件,一個使用了ES6語法js文件以及一個使用了sass語法的樣式文件,接下來我們就用npm script來實現(xiàn)這個簡單項目的自動化構(gòu)建(也即開發(fā)環(huán)境構(gòu)建任務(wù)流和生產(chǎn)環(huán)境構(gòu)建任務(wù)流)。

          簡單項目的自動化構(gòu)建就是npm script實現(xiàn)自動化構(gòu)建的使用場景。

          與日常開發(fā)一樣,我們這里也把這個工程構(gòu)建分為兩個部分,即開發(fā)環(huán)境構(gòu)建和生產(chǎn)環(huán)境構(gòu)建。下面先講講開發(fā)環(huán)境構(gòu)建的實現(xiàn):

          (一):開發(fā)環(huán)境構(gòu)建工程

          通過上面我們對開發(fā)環(huán)境構(gòu)建任務(wù)流的認(rèn)識,我們先理一理在這個項目中,開發(fā)環(huán)境任務(wù)流至少應(yīng)該包含哪些任務(wù):

          • 需要web開發(fā)服務(wù)器模擬生產(chǎn)環(huán)境以及實現(xiàn)源碼監(jiān)聽和自動刷新。
          • 對于sass文件,需要實時sass轉(zhuǎn)換,并且監(jiān)聽源碼變化重啟開發(fā)服務(wù)器、刷新瀏覽器。
          • 對于ES6文件,需要實時babel轉(zhuǎn)換,并且監(jiān)聽源碼變化重啟開發(fā)服務(wù)器、刷新瀏覽器。
          • 對于html文件,需要監(jiān)聽源碼變化重啟開發(fā)服務(wù)器、刷新瀏覽器。
          • ...

          對于sass和ES6修改源代碼后的實時轉(zhuǎn)換,我們可以通過加上一個watch參數(shù)實現(xiàn)。而對于所有這些需要監(jiān)聽變化的文件,我們則統(tǒng)一放入temp文件夾下(角色好比如nginx和Tomcat的應(yīng)用存放目錄),而后讓web開發(fā)服務(wù)器監(jiān)聽這個temp文件夾下所有文件的變化,一旦變化即重啟并刷新瀏覽器。

          好的經(jīng)過上面任務(wù)分析之后,我們可能會把package.json的scripts以及devDependencies寫成如下樣子(核心關(guān)注scripts中的start命令):

            "scripts": {
          "sassDev": "sass scss/main.scss temp/css/style.css --watch",
          "babelDev": "babel es6/script.js --out-dir temp/es5/script.js --watch",
          "copyHtmlDev": "copyfiles index.html temp",
          "serve": "browser-sync temp --files \"temp\"",
          "start": "run-p sassDev babelDev copyHtmlDev serve"
          },
          "devDependencies": {
          "@babel/cli": "^7.12.8",
          "@babel/core": "^7.12.9",
          "browser-sync": "^2.26.13",
          "copyfiles": "^2.4.1",
          "npm-run-all": "^4.1.5",
          "sass": "^1.29.0"
          }

          (二):生產(chǎn)環(huán)境構(gòu)建工程

          通過上面我們對生產(chǎn)環(huán)境構(gòu)建任務(wù)流的認(rèn)識,我們先理一理在這個項目中,生產(chǎn)環(huán)境任務(wù)流應(yīng)該包含哪些任務(wù):

          • 刪除上一次構(gòu)建結(jié)果任務(wù)
          • 編譯任務(wù)
          • html模板信息注入任務(wù)
          • 文件壓縮任務(wù)
          • ...

          好的經(jīng)過上面任務(wù)分析之后,我們可能會把package.json的scripts以及devDependencies寫成如下樣子(核心關(guān)注scripts中的build命令):

            "scripts": {
          "sass": "sass scss/main.scss dist/css/style.css",
          "babel": "babel es6 --out-dir dist/es5",
          "copyHtml": "copyfiles index.html dist",
          "build": "run-p sass babel copyHtml"
          },
          "devDependencies": {
          "@babel/cli": "^7.12.8",
          "@babel/core": "^7.12.9",
          "browser-sync": "^2.26.13",
          "copyfiles": "^2.4.1",
          "npm-run-all": "^4.1.5",
          "sass": "^1.29.0"
          }

          上述代碼實現(xiàn)不全,按道理說,在生產(chǎn)環(huán)境下,至少需要做代碼的兼容以及壓縮。這時我們就需要找到對應(yīng)的工具庫或者自己實現(xiàn),另外對于壓縮而言至少需要在編譯之后完成,所以需要注意多個任務(wù)間的關(guān)系。思路很簡單,我偷個懶當(dāng)前就不花時間去實踐了,需要時再實現(xiàn)就行。

          4.npm script構(gòu)建總結(jié)

          在進入Gulp實現(xiàn)前端工程的自動化構(gòu)建之前,我覺得有必要再重申一點:在項目以及構(gòu)建需求不復(fù)雜時,npm scripts就可以滿足我們的構(gòu)建需求了,無需借助其它工具。

          好的,下面進入gulp方式實現(xiàn)前端工程的自動化構(gòu)建。

          文章都寫到這份上了,不值得你點個贊和關(guān)注鼓勵一下嗎?

          三:實現(xiàn)前端工程的自動化構(gòu)建:gulp方式

          有些看官可能不太了解gulp,這里我先簡單介紹一下它吧。

          Gulp是一個基于流的自動化構(gòu)建工具,相比較于Grunt,它的構(gòu)建速度更快,任務(wù)編寫也更加簡單靈活。

          安裝好gulp之后,使用gulp的流程也就基本是如下這樣:

          • 首先需要在項目根目錄下創(chuàng)建一個Gulp入口文件gulpfile.js
          • 然后在這個入口文件中通過暴露函數(shù)的方式注冊任務(wù)
          • 最后以根目錄作為工作目錄執(zhí)行g(shù)ulp命令即可執(zhí)行注冊任務(wù)。

          有了以上了解之后,下面我們就探討如何借助gulp這個工具來實現(xiàn)自動化構(gòu)建吧。

          1.gulp完成各種任務(wù)調(diào)度

          (1):實現(xiàn)同步任務(wù)和異步任務(wù)

          對于新版本的Gulp來說,所有任務(wù)都是異步任務(wù),所以任務(wù)需要告訴Gulp什么時候執(zhí)行結(jié)束。以下是gulp異步任務(wù)實現(xiàn)的幾種方式(關(guān)注它們是如何通知Gulp異步任務(wù)結(jié)束的)。

          //?方式1:調(diào)用done方法主動通知任務(wù)結(jié)束
          exports.foo?=?done?=>?{
          ??console.log('foo?task?working~')
          ??done()?//?標(biāo)識任務(wù)執(zhí)行完成
          }
          //?方式2:返回Promise,通過它的resolve/reject方法通知任務(wù)結(jié)束
          const?timeout?=?time?=>?{
          ??return?new?Promise(resolve?=>?{
          ????setTimeout(resolve,?time)
          ??})
          }
          //?方式3:返回讀取流對象,流完即自動通知任務(wù)結(jié)束
          exports.stream?=?()?=>?{
          ??const?read?=?fs.createReadStream('yarn.lock')
          ??const?write?=?fs.createWriteStream('a.txt')
          ??read.pipe(write)
          ??return?read
          }
          //?更多方式

          (2):實現(xiàn)并行任務(wù)和串行任務(wù)

          并行任務(wù)和串行任務(wù)可以通過gulp提供的series(串行), parallel(并行)實現(xiàn)。

          const?{?series,?parallel?}?=?require('gulp');

          const?task1?=?done?=>?{
          ??setTimeout(()?=>?{
          ????console.log('task1?working~');
          ????done();
          ??},?1000)
          }

          const?task2?=?done?=>?{
          ??setTimeout(()?=>?{
          ????console.log('task2?working~');
          ????done();
          ??},?1000)??
          }

          exports.bar?=?parallel(task1,?task2);?//?并行任務(wù)bar

          exports.foo?=?series(task1,?task2);?//?串行任務(wù)foo

          (3): gulp插件任務(wù)

          Gulp生態(tài)中有很多成熟的gulp任務(wù)插件,使用它們可以很好地提高效率,如以下示例:

          const?{?src,?dest?}?=?require('gulp');
          const?cleanCSS?=?require('gulp-clean-css');
          const?rename?=?require('gulp-rename');

          exports.default?=?()?=>?{
          ??return?src('src/*.css')
          ????.pipe(cleanCSS())
          ????.pipe(rename({?extname:?'.min.css'?}))
          ????.pipe(dest('dist'))
          }

          (4): 自定義gulp任務(wù)

          如果需要定制任務(wù),或者對于我們的需求沒有較好的gulp插件,那么我們就需要自定義任務(wù),如下示例:

          const?fs?=?require('fs')
          const?{?Transform?}?=?require('stream')

          exports.default?=?()?=>?{
          ??const?readStream?=?fs.createReadStream('normalize.css');
          ??const?writeStream?=?fs.createWriteStream('normalize.min.css');
          ??//?文件轉(zhuǎn)換流
          ??const?transformStream?=?new?Transform({
          ????//?核心轉(zhuǎn)換過程
          ????transform:?(chunk,?encoding,?callback)?=>?{
          ??????const?input?=?chunk.toString();
          ??????const?output?=?input.replace(/\s+/g,?'').replace(/\/\*.+?\*\//g,?'');
          ??????callback(null,?output);
          ????}
          ??})

          ??return?readStream
          ????.pipe(transformStream)?//?轉(zhuǎn)換
          ????.pipe(writeStream)?//?寫入
          }

          2.gulp完成構(gòu)建任務(wù)流

          如下gulpfile文件,分為開發(fā)環(huán)境構(gòu)建(develop任務(wù))和生產(chǎn)環(huán)境構(gòu)建(build任務(wù))。相對于理論認(rèn)識,工具的使用只是不同實現(xiàn)方式,這里就不多贅述了,具體的邏輯可以看下面代碼中的注釋,我為您寫的很清楚了哦。

          const?{
          ??src,
          ??dest,
          ??parallel,
          ??series,
          ??watch
          }?=?require('gulp')

          const?del?=?require('del')
          const?browserSync?=?require('browser-sync')

          const?loadPlugins?=?require('gulp-load-plugins')

          const?plugins?=?loadPlugins()
          const?bs?=?browserSync.create()

          const?data?=?{
          ??menus:?[{
          ??????name:?'Home',
          ??????icon:?'aperture',
          ??????link:?'index.html'
          ????},
          ????{
          ??????name:?'Features',
          ??????link:?'features.html'
          ????},
          ????{
          ??????name:?'About',
          ??????link:?'about.html'
          ????},
          ????{
          ??????name:?'Contact',
          ??????link:?'#',
          ??????children:?[{
          ??????????name:?'Twitter',
          ??????????link:?'https://twitter.com/w_zce'
          ????????},
          ????????{
          ??????????name:?'About',
          ??????????link:?'https://weibo.com/zceme'
          ????????},
          ????????{
          ??????????name:?'divider'
          ????????},
          ????????{
          ??????????name:?'About',
          ??????????link:?'https://github.com/zce'
          ????????}
          ??????]
          ????}
          ??],
          ??pkg:?require('./package.json'),
          ??date:?new?Date()
          }
          //?css編譯??src?=>?temp
          const?style?=?()?=>?{
          ??return?src('src/assets/styles/*.scss',?{
          ??????base:?'src'
          ????})
          ????.pipe(plugins.sass({
          ??????outputStyle:?'expanded'
          ????}))
          ????.pipe(dest('temp'))
          ????.pipe(bs.reload({
          ??????stream:?true
          ????}))
          }
          //?js編譯???src?=>?temp
          const?script?=?()?=>?{
          ??return?src('src/assets/scripts/*.js',?{
          ??????base:?'src'
          ????})
          ????.pipe(plugins.babel({
          ??????presets:?['@babel/preset-env']
          ????}))
          ????.pipe(dest('temp'))
          ????.pipe(bs.reload({
          ??????stream:?true
          ????}))
          }

          //?html模板解析?????src?=>?temp
          const?page?=?()?=>?{
          ??return?src('src/*.html',?{
          ??????base:?'src'
          ????})
          ????.pipe(plugins.swig({
          ??????data,
          ??????defaults:?{
          ????????cache:?false
          ??????}
          ????}))?//?防止模板緩存導(dǎo)致頁面不能及時更新
          ????.pipe(dest('temp'))
          ????.pipe(bs.reload({
          ??????stream:?true
          ????}))
          }

          //?串行編譯、模板解析
          const?compile?=?parallel(style,?script,?page)

          //?開發(fā)環(huán)境開發(fā)服務(wù)器
          const?serve?=?()?=>?{
          ??watch('src/assets/styles/*.scss',?style)
          ??watch('src/assets/scripts/*.js',?script)
          ??watch('src/*.html',?page)
          ??//?watch('src/assets/images/**',?image)
          ??//?watch('src/assets/fonts/**',?font)
          ??//?watch('public/**',?extra)
          ??watch([
          ????'src/assets/images/**',
          ????'src/assets/fonts/**',
          ????'public/**'
          ??],?bs.reload)

          ??bs.init({
          ????notify:?false,
          ????port:?2080,
          ????//?open:?false,
          ????//?files:?'dist/**',
          ????server:?{
          ??????baseDir:?['temp',?'src',?'public'],
          ??????routes:?{
          ????????'/node_modules':?'node_modules'
          ??????}
          ????}
          ??})
          }

          //?開發(fā)環(huán)境構(gòu)建流:編譯?+?啟動開發(fā)服務(wù)器??? src => temp
          const?develop?=?series(compile,?serve)



          //?生產(chǎn)環(huán)境下清空文件夾
          const?clean?=?()?=>?{
          ??return?del(['dist',?'temp'])
          }
          //?生產(chǎn)環(huán)境js、css、html壓縮后構(gòu)建??temp?=>?dist
          const?useref?=?()?=>?{
          ??return?src('temp/*.html',?{
          ??????base:?'temp'
          ????})
          ????.pipe(plugins.useref({
          ??????searchPath:?['temp',?'.']
          ????}))
          ????//?html?js?css
          ????.pipe(plugins.if(/\.js$/,?plugins.uglify()))
          ????.pipe(plugins.if(/\.css$/,?plugins.cleanCss()))
          ????.pipe(plugins.if(/\.html$/,?plugins.htmlmin({
          ??????collapseWhitespace:?true,
          ??????minifyCSS:?true,
          ??????minifyJS:?true
          ????})))
          ????.pipe(dest('dist'))
          }
          //?生產(chǎn)環(huán)境圖片壓縮后構(gòu)建???src?=>?dist
          const?image?=?()?=>?{
          ??return?src('src/assets/images/**',?{
          ??????base:?'src'
          ????})
          ????.pipe(plugins.imagemin())
          ????.pipe(dest('dist'))
          }
          //?生產(chǎn)環(huán)境字體壓縮后構(gòu)建???src?=>?dist
          const?font?=?()?=>?{
          ??return?src('src/assets/fonts/**',?{
          ??????base:?'src'
          ????})
          ????.pipe(plugins.imagemin())
          ????.pipe(dest('dist'))
          }
          //?生產(chǎn)環(huán)境靜態(tài)資源構(gòu)建
          const?extra?=?()?=>?{
          ??return?src('public/**',?{
          ??????base:?'public'
          ????})
          ????.pipe(dest('dist'))
          }

          //?上線之前執(zhí)行的任務(wù)???src?=>?(temp?=>)?=>?dist?
          const?build?=?series(
          ??clean,
          ??parallel(
          ????series(compile,?useref),
          ????image,
          ????font,
          ????extra
          ??)
          )

          module.exports?=?{
          ??clean,
          ??build,
          ??develop
          }

          四:其它方式實現(xiàn)前端工程的自動化構(gòu)建

          在前端工程的自動化構(gòu)建發(fā)展歷程中,出現(xiàn)了很多的自動化工具。如grunt、gulp、webpack,包括現(xiàn)在正處在風(fēng)口浪尖的vite等等。webpack的相關(guān)內(nèi)容會在另外一篇文章中探討,對于其它的構(gòu)建工具以及過時的工具我覺得沒有現(xiàn)在學(xué)習(xí)的必要,具體生產(chǎn)需要使用時學(xué)習(xí)即可。

          總的來說,工具很多,但是最重要的其實是對于自動化構(gòu)建本身的理論認(rèn)識,而對于自動化構(gòu)建的實現(xiàn)及其工具而言,我覺得,包括比較需要掌握的gulp和webpack,完全理解npm script方式是更重要的。


          ??? 最后


          當(dāng)然也可以關(guān)注我的公眾號:前端獵手,或是添加我的微信wKavin私底下進行交流。


          瀏覽 36
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费在线成人网 | 91dajiba | 久久噜噜噜久久熟女-久久久噜噜噜 | 伊人大香在线 | www.精品在线播放国产区 |