亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

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

Zoom / 1523人閱讀

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

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

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

寫在開頭

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

和這樣的:

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

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

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

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

在很長的一段前端歷史里,是不存在打包這個(gè)說法的。那個(gè)時(shí)候頁面基本是純靜態(tài)的或者服務(wù)端輸出的,沒有 AJAX,也沒有 jQuery。那個(gè)時(shí)候的 JavaScript 就像個(gè)玩具,用處大概就是在側(cè)欄弄個(gè)時(shí)鐘,用 media player 放個(gè) 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ù)處理和模板語言的福,我們的編譯腳本也洋洋灑灑寫了百來行。命令行腳本有個(gè)不好的地方,就是 windows 和 mac/linux 是不通用的,如果有跨平臺需求的話,windows 要裝個(gè)可以執(zhí)行 bash 腳本的命令行工具,比如 msys(目前最新的是 msys2),或者使用 php 或 python 等其他語言的腳本來編寫,對于非全棧型的前端程序員來說,寫 bash / php / python 還是很生澀的。因此我們需要一個(gè)簡單的打包工具,可以利用各種編譯工具,編譯 / 壓縮 js、css、html、圖片等資源。然后 Grunt 產(chǎn)生了(2012 年),配置文件格式是我們最愛的 js,寫法也很簡單,社區(qū)有非常多的插件支持各種編譯、lint、測試工具。一年多后另一個(gè)打包工具 gulp 誕生了,擴(kuò)展性更強(qiáng),采用流式處理效率更高。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

因?yàn)樯厦嬉稽c(diǎn) Browserify 對資源文件的加載支持不夠完善,導(dǎo)致打包時(shí)一般都要配合 gulp 或 grunt 一塊使用,無謂地增加了打包的難度。

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

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

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

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

安裝 Node.js

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

初始化一個(gè)項(xiàng)目

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

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

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

npm init

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

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

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

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

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

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

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

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 編譯的時(shí)候檢查代碼,如果有錯誤,webpack 會報(bào)錯。

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

Visual Studio Code 需要安裝 ESLint 擴(kuò)展

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

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

寫幾個(gè)頁面

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



  
    
  

  
  

它是一個(gè)空白頁面,注意這里我們不需要自己寫 , 因?yàn)榇虬蟮奈募吐窂娇赡軙?,所以我們?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() {
    // 點(diǎn)擊瀏覽器后退 / 前進(jìn)按鈕時(shí)會觸發(fā) window.onpopstate 事件,我們在這時(shí)切換到相應(yīng)頁面
    // https://developer.mozilla.org/en-US/docs/Web/Events/popstate
    window.addEventListener("popstate", () => {
      this.load(location.pathname)
    })

    // 打開頁面時(shí)加載當(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)建頁面實(shí)例
    const view = new routes[path]()
    // 調(diào)用頁面方法,把頁面加載到 document.body 中
    view.mount(document.body)
  }
}

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

src/views/foo/index.js:

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

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

// 引入 css, 會生成 

      <