国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Webpack 4 和單頁應(yīng)用入門

Zoom / 1362人閱讀

摘要:但由于和技術(shù)過于和復(fù)雜,并沒能得到廣泛的推廣。但是在瀏覽器內(nèi)并不適用。依托模塊化編程,的實現(xiàn)方式更為簡單清晰,一個網(wǎng)頁不再是傳統(tǒng)的類似文檔的頁面,而是一個完整的應(yīng)用程序。到了這里,我們的主角登場了年此處應(yīng)有掌聲。和差不多同期登場的還有。

Github:https://github.com/fenivana/w...

webpack 更新到了 4.0,官網(wǎng)還沒有更新文檔。因此把教程更新一下,方便大家用起 webpack 4。

寫在開頭

先說說為什么要寫這篇文章,最初的原因是組里的小朋友們看了 webpack 文檔后,表情都是這樣的:摘自 webpack 一篇文檔的評論區(qū))

和這樣的:

是的,即使是外國佬也在吐槽這文檔不是人能看的。回想起當(dāng)年自己啃 webpack 文檔的血與淚的往事,覺得有必要整一個教程,可以讓大家看完后愉悅地搭建起一個 webpack 打包方案的項目。

官網(wǎng)新的 webpack 文檔現(xiàn)在寫的很詳細(xì)了,能看英文的小伙伴可以直接去看官網(wǎng)。

可能會有人問 webpack 到底有什么用,你不能上來就糊我一臉代碼讓我馬上搞,我照著搞了一遍結(jié)果根本沒什么用,都是騙人的。所以,在說 webpack 之前,我想先談一下前端打包方案這幾年的演進(jìn)歷程,在什么場景下,我們遇到了什么問題,催生出了應(yīng)對這些問題的工具。了解了需求和目的之后,你就知道什么時候 webpack 可以幫到你。我希望我用完之后很爽,你們用完之后也是。

先說說前端打包方案的黑暗歷史

在很長的一段前端歷史里,是不存在打包這個說法的。那個時候頁面基本是純靜態(tài)的或者服務(wù)端輸出的,沒有 AJAX,也沒有 jQuery。那個時候的 JavaScript 就像個玩具,用處大概就是在側(cè)欄弄個時鐘,用 media player 放個 mp3 之類的腳本,代碼量不是很多,直接放在

以上是 AMD 規(guī)范的基本用法,更詳細(xì)的就不多說了(反正也淘汰了~),有興趣的可以看 這里。

js 模塊化問題基本解決了,css 和 html 也沒閑著。什么 less,sass,stylus 的 css 預(yù)處理器橫空出世,說能幫我們簡化 css 的寫法,自動給你加 vendor prefix。html 在這期間也出現(xiàn)了一堆模板語言,什么 handlebars,ejs,jade,可以把 ajax 拿到的數(shù)據(jù)插入到模板中,然后用 innerHTML 顯示到頁面上。

托 AMD 和 CSS 預(yù)處理和模板語言的福,我們的編譯腳本也洋洋灑灑寫了百來行。命令行腳本有個不好的地方,就是 windows 和 mac/linux 是不通用的,如果有跨平臺需求的話,windows 要裝個可以執(zhí)行 bash 腳本的命令行工具,比如 msys(目前最新的是 msys2),或者使用 php 或 python 等其他語言的腳本來編寫,對于非全棧型的前端程序員來說,寫 bash / php / python 還是很生澀的。因此我們需要一個簡單的打包工具,可以利用各種編譯工具,編譯 / 壓縮 js、css、html、圖片等資源。然后 Grunt 產(chǎn)生了(2012 年),配置文件格式是我們最愛的 js,寫法也很簡單,社區(qū)有非常多的插件支持各種編譯、lint、測試工具。一年多后另一個打包工具 gulp 誕生了,擴展性更強,采用流式處理效率更高。

依托 AMD 模塊化編程,SPA(Single-page application) 的實現(xiàn)方式更為簡單清晰,一個網(wǎng)頁不再是傳統(tǒng)的類似 word 文檔的頁面,而是一個完整的應(yīng)用程序。SPA 應(yīng)用有一個總的入口頁面,我們通常把它命名為 index.html、app.html、main.html,這個 html 的 一般是空的,或者只有總的布局(layout),比如下圖:

布局會把 header、nav、footer 的內(nèi)容填上,但 main 區(qū)域是個空的容器。這個作為入口的 html 最主要的工作是加載啟動 SPA 的 js 文件,然后由 js 驅(qū)動,根據(jù)當(dāng)前瀏覽器地址進(jìn)行路由分發(fā),加載對應(yīng)的 AMD 模塊,然后該 AMD 模塊執(zhí)行,渲染對應(yīng)的 html 到頁面指定的容器內(nèi)(比如圖中的 main)。在點擊鏈接等交互時,頁面不會跳轉(zhuǎn),而是由 js 路由加載對應(yīng)的 AMD 模塊,然后該 AMD 模塊渲染對應(yīng)的 html 到容器內(nèi)。

雖然 AMD 模塊讓 SPA 更容易地實現(xiàn),但小問題還是很多的:

不是所有的第三方庫都是 AMD 規(guī)范的,這時候要配置 shim,很麻煩。

雖然 RequireJS 支持通過插件把 html 作為依賴加載,但 html 里面的 的路徑是個問題,需要使用絕對路徑并且保持打包后的圖片路徑和打包前的路徑不變,或者使用 html 模板語言把 src 寫成變量,在運行時生成。

不支持動態(tài)加載 css,變通的方法是把所有的 css 文件合并壓縮成一個文件,在入口的 html 頁面一次性加載。

SPA 項目越做越大,一個應(yīng)用打包后的 js 文件到了幾 MB 的大小。雖然 r.js 支持分模塊打包,但配置很麻煩,因為模塊之間會互相依賴,在配置的時候需要 exclude 那些通用的依賴項,而依賴項要在文件里一個個檢查。

所有的第三方庫都要自己一個個的下載,解壓,放到某個目錄下,更別提更新有多麻煩了。雖然可以用 npm 包管理工具,但 npm 的包都是 CommonJS 規(guī)范的,給后端 Node.js 用的,只有部分支持 AMD 規(guī)范,而且在 npm 3 之前,這些包有依賴項的話也是不能用的。后來有個 bower 包管理工具是專門的 web 前端倉庫,這里的包一般都支持 AMD 規(guī)范。

AMD 規(guī)范定義和引用模塊的語法太麻煩,上面介紹的 AMD 語法僅是最簡單通用的語法,API 文檔里面還有很多變異的寫法,特別是當(dāng)發(fā)生循環(huán)引用的時候(a 依賴 b,b 依賴 a),需要使用其他的 語法 解決這個問題。而且 npm 上很多前后端通用的庫都是 CommonJS 的語法。后來很多人又開始嘗試使用 ES6 模塊規(guī)范,如何引用 ES6 模塊又是一個大問題。

項目的文件結(jié)構(gòu)不合理,因為 grunt/gulp 是按照文件格式批量處理的,所以一般會把 js、html、css、圖片分別放在不同的目錄下,所以同一個模塊的文件會散落在不同的目錄下,開發(fā)的時候找文件是個麻煩的事情。code review 時想知道一個文件是哪個模塊的也很麻煩,解決辦法比如又要在 imgs 目錄下建立按模塊命名的文件夾,里面再放圖片。

到了這里,我們的主角 webpack 登場了(2012 年)(此處應(yīng)有掌聲)。

和 webpack 差不多同期登場的還有 Browserify。這里簡單介紹一下 Browserify。Browserify 的目的是讓前端也能用 CommonJS 的語法 require("module") 來加載 js。它會從入口 js 文件開始,把所有的 require() 調(diào)用的文件打包合并到一個文件,這樣就解決了異步加載的問題。那么 Browserify 有什么不足之處導(dǎo)致我不推薦使用它呢? 主要原因有下面幾點:

最主要的一點,Browserify 不支持把代碼打包成多個文件,在有需要的時候加載。這就意味著訪問任何一個頁面都會全量加載所有文件。

Browserify 對其他非 js 文件的加載不夠完善,因為它主要解決的是 require() js 模塊的問題,其他文件不是它關(guān)心的部分。比如 html 文件里的 img 標(biāo)簽,它只能轉(zhuǎn)成 Data URI 的形式,而不能替換為打包后的路徑。

因為上面一點 Browserify 對資源文件的加載支持不夠完善,導(dǎo)致打包時一般都要配合 gulp 或 grunt 一塊使用,無謂地增加了打包的難度。

Browserify 只支持 CommonJS 模塊規(guī)范,不支持 AMD 和 ES6 模塊規(guī)范,這意味舊的 AMD 模塊和將來的 ES6 模塊不能使用。

基于以上幾點,Browserify 并不是一個理想的選擇。那么 webpack 是否解決了以上的幾個問題呢? 廢話,不然介紹它干嘛。那么下面章節(jié)我們用實戰(zhàn)的方式來說明 webpack 是怎么解決上述的問題的。

上手先搞一個簡單的 SPA 應(yīng)用

一上來步子太大容易扯到蛋,讓我們先弄個最簡單的 webpack 配置來熱一下身。

安裝 Node.js

webpack 是基于我大 Node.js 的打包工具,上來第一件事自然是先安裝 Node.js 了,傳送門 ->。

初始化一個項目

我們先隨便找個地方,建一個文件夾叫 simple, 然后在這里面搭項目。完成品在 examples/simple 目錄,大家搞的時候可以參照一下。我們先看一下目錄結(jié)構(gòu):

├── dist                      打包輸出目錄,只需部署這個目錄到生產(chǎn)環(huán)境
├── package.json              項目配置信息
├── node_modules              npm 安裝的依賴包都在這里面
├── src                       我們的源代碼
│   ├── components            可以復(fù)用的模塊放在這里面
│   ├── index.html            入口 html
│   ├── index.js              入口 js
│   ├── shared                公共函數(shù)庫
│   └── views                 頁面放這里
└── webpack.config.js         webpack 配置文件

打開命令行窗口,cd 到剛才建的 simple 目錄。然后執(zhí)行這個命令初始化項目:

npm init

命令行會要你輸入一些配置信息,我們這里一路按回車下去,生成一個默認(rèn)的項目配置文件 package.json

給項目加上語法報錯和代碼規(guī)范檢查

我們安裝 eslint, 用來檢查語法報錯,當(dāng)我們書寫 js 時,有錯誤的地方會出現(xiàn)提示。

npm install eslint eslint-config-enough eslint-loader --save-dev

npm install 可以一條命令同時安裝多個包,包之間用空格分隔。包會被安裝進(jìn) node_modules 目錄中。

--save-dev 會把安裝的包和版本號記錄到 package.json 中的 devDependencies 對象中,還有一個 --save, 會記錄到 dependencies 對象中,它們的區(qū)別,我們可以先簡單的理解為打包工具和測試工具用到的包使用 --save-dev 存到 devDependencies, 比如 eslint、webpack。瀏覽器中執(zhí)行的 js 用到的包存到 dependencies, 比如 jQuery 等。那么它們用來干嘛的?

因為有些 npm 包安裝是需要編譯的,那么導(dǎo)致 windows / mac /linux 上編譯出的可執(zhí)行文件是不同的,也就是無法通用,因此我們在提交代碼到 git 上去的時候,一般都會在 .gitignore 里指定忽略 node_modules 目錄和里面的文件,這樣其他人從 git 上拉下來的項目是沒有 node_modules 目錄的,這時我們需要運行

npm install

它會讀取 package.json 中的 devDependenciesdependencies 字段,把記錄的包的相應(yīng)版本下載下來。

這里 eslint-config-enough 是配置文件,它規(guī)定了代碼規(guī)范,要使它生效,我們要在 package.json 中添加內(nèi)容:

{
  "eslintConfig": {
    "extends": "enough",
    "env": {
      "browser": true,
      "node": true
    }
  }
}

業(yè)界最有名的語法規(guī)范是 airbnb 出品的,但它規(guī)定的太死板了,比如不允許使用 for-offor-in 等。感興趣的同學(xué)可以參照 這里 安裝使用。

eslint-loader 用于在 webpack 編譯的時候檢查代碼,如果有錯誤,webpack 會報錯。

項目里安裝了 eslint 還沒用,我們的 IDE 和編輯器也得要裝 eslint 插件支持它。

Visual Studio Code 需要安裝 ESLint 擴展

atom 需要安裝 linter 和 linter-eslint 這兩個插件,裝好后重啟生效。

WebStorm 需要在設(shè)置中打開 eslint 開關(guān):

寫幾個頁面

我們寫一個最簡單的 SPA 應(yīng)用來介紹 SPA 應(yīng)用的內(nèi)部工作原理。首先,建立 src/index.html 文件,內(nèi)容如下:



  
    
  

  
  

它是一個空白頁面,注意這里我們不需要自己寫 , 因為打包后的文件名和路徑可能會變,所以我們用 webpack 插件幫我們自動加上。

src/index.js:

// 引入 router
import router from "./router"

// 啟動 router
router.start()

src/router.js:

// 引入頁面文件
import foo from "./views/foo"
import bar from "./views/bar"

const routes = {
  "/foo": foo,
  "/bar": bar
}

// Router 類,用來控制頁面根據(jù)當(dāng)前 URL 切換
class Router {
  start() {
    // 點擊瀏覽器后退 / 前進(jìn)按鈕時會觸發(fā) window.onpopstate 事件,我們在這時切換到相應(yīng)頁面
    // https://developer.mozilla.org/en-US/docs/Web/Events/popstate
    window.addEventListener("popstate", () => {
      this.load(location.pathname)
    })

    // 打開頁面時加載當(dāng)前頁面
    this.load(location.pathname)
  }

  // 前往 path,變更地址欄 URL,并加載相應(yīng)頁面
  go(path) {
    // 變更地址欄 URL
    history.pushState({}, "", path)
    // 加載頁面
    this.load(path)
  }

  // 加載 path 路徑的頁面
  load(path) {
    // 首頁
    if (path === "/") path = "/foo"
    // 創(chuàng)建頁面實例
    const view = new routes[path]()
    // 調(diào)用頁面方法,把頁面加載到 document.body 中
    view.mount(document.body)
  }
}

// 導(dǎo)出 router 實例
export default new Router()

src/views/foo/index.js:

// 引入 router
import router from "../../router"

// 引入 html 模板,會被作為字符串引入
import template from "./index.html"

// 引入 css, 會生成