webpack 從入門到放棄

webpack 從入門到放棄

隨着前端項目複雜程度愈來愈高,依賴也愈來愈多,爲了提升項目中代碼的可複用性,前端開始提出模塊化開發的思路,前端模塊化會有如下幾個痛點:css

  1. 命名衝突
  2. 文件依賴
  3. 代碼複用

模塊化,會將相關的代碼封裝成一個package包的文件,當須要的時候,直接拿來用便可(import引入)。
至於相關文件的直接依賴如何處理,webpack會幫咱們解決這個問題。html

那麼模塊化應該使用什麼樣的規範呢?常見的模塊化的標準主要以下:前端

  • commonJsnode

    nodejs使用的就是commonJs的規範,採用的同步方式加載依賴,一個文件就是一個模塊。react

    導入導出方式以下:webpack

    導入:const aa = require('./aa')
    導出:module.exports = aa.fun

    缺點是加載的模塊是同步的,只有加載完才能執行後面的操做。由於 node.js 的模塊文件通常存在於本地硬盤,因此通常不會出現這個問題,可是在瀏覽器環境該規範就不那麼適用了。web

  • AMDnpm

    由於commonJS不適用於瀏覽器的環境,因此出現AMD規範。特色: 異步加載/推崇依賴前置、提早執行 。require.js最佳實踐json

    使用方式:segmentfault

    定義模塊: define()
    加載模塊:require()
    引用:require.config()
  • CMD

    CMD的使用方式如上,可是特色不太同樣。CMD是異步加載/依賴就近、延遲執行 sea.js最佳實踐

  • ES6

    ES6 直接在語言層面上實現了模塊化。咱們如今用的最多的就是 ES6 模塊化的實踐方式。

    導入導出方式以下:

    導入:
    import aa from 'aa'
    import {A} from 'aa'
    
    導出:
    export default {A, B}
    export {A, B}
    export funtion aa() {}

    雖然ES6是模塊化的最終方案,可是仍是在許多瀏覽器上有兼容問題,須要對代碼進行轉碼處理才行。

  • 樣式文件中的模塊化

    前端開發中,樣式文件也開始支持模塊化,以stylus爲例,一般將一些通用的文件放到文件中,在使用相關的樣式時,直接@import引入文件,就能使用對應的代碼片斷,固然也能定義一些全局的參數(顏色,圓角類)進行使用。

    // common.styl
    .center-transform
      top 50%
      left 50%
      transform translate(-50% -50%)
    center-transform()
      top 50%
      left 50%
      transform translate(-50% -50%)
    
    // 使用
    @import 'common.styl'
    .box {
      center-transform
    }

webpack和Gulp/Grunt、Rollup比較

  • Grunt: 是一套前端自動化工具,幫助處理反覆重複的任務。通常用於:編譯,壓縮,合併文件,簡單語法檢查等
  • Gulp: 是基於「流」的自動化構建工具,採用代碼優於配置的策略,更易於學習和使用
  • Rollup: Rollup 是一個和 Webpack 很相似但專一於 ES6 的模塊打包工具。 Rollup 的亮點在於能針對 ES6 源碼進行 Tree Shaking 以去除那些已被定義但沒被使用的代碼,以及 Scope Hoisting 以減少輸出文件大小提高運行性能。 可是Rollup 生態鏈還不完善,體驗不如 Webpack。
  • webpack: Webpack 是模塊化管理工具和打包工具。經過 loader 的轉換,任何形式的資源均可以視做模塊,好比 CommonJs 模塊、AMD 模塊、ES6 模塊、CSS、圖片等。它能夠將許多鬆散的模塊按照依賴和規則打包成符合生產環境部署的前端資源。還能夠將按需加載的模塊進行代碼分隔,等到實際須要的時候再異步加載

開始使用webpack

首先建立一下的目錄結構:

.
├── src
│   ├── assemble
│   │   ├── css
│   │   │   ├── index.css
│   │   ├── index.html
│   │   └── js
│   │       ├── index.js
│   │       └── test.js
│   ├── babyTest
│   │   ├── css
│   │   │   └── index.css
│   │   ├── index.html
│   │   └── js
│   │       └── index.js


文件內容:
// 1. assemble-index.html: 
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
</body>
</html>

// 2. assemble-css/index.css:
body {background: red} 

// 3. assemble-js/index.js:
import '../css/index.css'
console.log('index.js')


// 4. assemble-js/test.js:
console.log('test.js')

babyTest目錄和上面相似
  1. 建立package.json文件: npm init
  2. 安裝webpack(全局、目錄安裝):npm install webpack -D
  3. 建立webpack.config.js文件

    下面直接配置的是多文件入口:
    // 引入插件
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    // 相關配置
    module.exports = {
     mode: 'development', // 指定webpack的模式  
     entry: {
       'assemble/js/index': './src/assemble/js/index.js',
       'assemble/js/test': './src/assemble/js/test.js',
       'babyTest/js/index': './src/babyTest/js/index.js'
     },
     output: {
       filename: '[name].js',  // 打包後輸出文件的文件名
       path: path.resolve('./output/market') // 打包後的文件存放的地方
     },
     module: {
       rules: [
         {
           test: /\.css$/,
           use: ['style-loader', 'css-loader']
         }
       ]
     },
     plugins: [
       new HtmlWebpackPlugin({
         template: './src/assemble/index.html',
         filename: 'assemble/index.html',
         chunks: ['assemble/js/index']
       }),
       new HtmlWebpackPlugin({
         template: './src/babyTest/index.html',
         filename: 'babyTest/index.html',
         hash: true,
         chunks: ['babyTest/js/index']
       })
     ]
    }

    上面寫的實例中,將loader和plugins已經使用了,能夠先按照上面的使用,後邊將進行詳細方法的介紹。

    使用前,安裝對應的依賴包

    npm install css-loader style-loader html-webpack-plugin -D
    備註:

    mode,參考 模式

    多文件入口配置,參考 多頁面應用程序

  4. 終端執行打包命令: webpack

能夠看到在根目錄下有output目錄,裏面就行對應的打包文件。直接運行output文件下的目錄,可以看到對應效果,css和js都可以執行成功。

備註:
執行打包命令的方式有如下幾種方式

  1. node_modules/.bin/webpack
  2. webpack
  3. 在package.json文件中配置對應的命令 "scripts": { "start": "webpack"}

entry

入口起點(entry point)指示 webpack 應該使用哪一個模塊,來做爲構建其內部依賴圖的開始。進入入口起點後,webpack 會找出有哪些模塊和庫是入口起點(直接和間接)依賴的。

每一個依賴項隨即被處理,最後輸出到稱之爲 bundles 的文件中,,entry屬性 來指定一個入口起點(或多個入口起點)。默認值爲 ./src。

output

output 屬性告訴 webpack 在哪裏輸出它所建立的 bundles,以及如何命名這些文件,默認值爲 ./dist。基本上,整個應用程序結構,都會被編譯到你指定的輸出路徑的文件夾中。

Loader

loader 用於對模塊的源代碼進行轉換。loader 可使你在 import 或"加載"模塊時預處理文件。所以,loader 相似於其餘構建工具中「任務(task)」,並提供了處理前端構建步驟的強大方法。loader 能夠將文件從不一樣的語言(如 TypeScript)轉換爲 JavaScript,或將內聯圖像轉換爲 data URL。loader 甚至容許你直接在 JavaScript 模塊中 import CSS文件!

上面的配置中就用到了 css-loaderstyle-loader,主要是在對引用的css文件會用style-loadercss-loader進行處理,當配置多個loader的時候,按照從左至右的方式進行處理。

Loaders的配置主要包含如下配置:

  1. test(必填): 用正則匹配對應文件的擴展名
  2. use(必填):loader的名稱
  3. include/exclude(非必填):手動添加必須處理或者是忽略的文件
  4. query(非必填):爲loaders提供額外的設置選項

在webpack中使用的方式

  1. 命令行調用:webpack --module-bind jade --module-bind 'css=style!css'
  2. 經過require:require('style-loader!css-loader?minimize!./main.css')
  3. 使用配置文件: 如上配置

聯繫緊密的Babel

Babel是一個編譯JavaScript的平臺,能夠幫咱們將編譯的代碼

  • 讓你能使用最新的JavaScript代碼(ES6,ES7...),而不用管新標準是否被當前使用的瀏覽器徹底支持
  • 讓你能使用基於JavaScript進行了拓展的語言

Babel的安裝與使用

  1. Babel的安裝

Babel實際上是幾個模塊化的包,其核心功能稱爲babel-core的npm包中,webpack能夠把其不一樣的包整合在一塊兒使用,對於每個你須要的功能或拓展,你都須要安裝單獨的包(用的最多的就是解析ES6語法的包 babel-preset-env)
npm install --save-dev babel-core babel-loader babel-preset-env

在webpack.config.js中,module的rules中添加;

{
  test: /\.js$/,
  use: {
    loader: 'babel-loader',
    options: {
      presets: [
        'env', 'react'
      ]
    }
  },
  include: /src/,
  exclude: /node_modules/
}
  1. Babel的配置

Babel的配置能夠直接在webpack.config.js中進行配置,可是有時配置項過多,但在這個文件中配置過多js編譯規則的代碼,顯得可讀性不太好,所以支持在.babelrc中單獨配置,webpack會自動調用這個文件中的配置項。

// .babelrc文件
{
  "presets": ["react", "env"]
}

loader的特性(引用官網)

  • loader 支持鏈式傳遞。可以對資源使用流水線(pipeline)。一組鏈式的 loader 將按照相反的順序執行。loader 鏈中的第一個 loader 返回值給下一個 loader。在最後一個 loader,返回 webpack 所預期的 JavaScript。
  • loader 能夠是同步的,也能夠是異步的。
  • loader 運行在 Node.js 中,而且可以執行任何可能的操做。
  • loader 接收查詢參數。用於對 loader 傳遞配置。
  • loader 也可以使用 options 對象進行配置。
  • 除了使用 package.json 常見的 main 屬性,還能夠將普通的 npm 模塊導出爲 loader,作法是在 package.json 裏定義一個 loader 字段。
  • 插件(plugin)能夠爲 loader 帶來更多特性。
  • loader 可以產生額外的任意文件。

擴展-常使用的loader清單

loader name 介紹
css-loader 解析@import 和 Url()引用的css文件,轉化成 import/require() 的方式而後在解析他們
style-loader 將 CSS 放在 <style></style> 標籤中注入到 DOM 中
sass-loader 將 SASS/SCSS 轉換爲 css
less-loader 將 less 轉化爲 css
html-loader 將 html 輸出爲字符串,也能夠根據配置進行壓縮
babel-loader 加載 ES2015+ 代碼,而後使用 Babel 轉譯爲 ES5
url-loader 將文件加載爲 Base64 編碼的 URL
file-loader 能夠解析項目中的url引入(不只限於css),根據咱們的配置

...更多請查看上面的連接

plugin

插件是 webpack 的支柱功能。webpack 自身也是構建於,你在 webpack 配置中用到的相同的插件系統之上!

插件目的在於解決 loader 沒法實現的其餘事。

Plugins在構建的過程當中,經過在構建流程中注入對應的鉤子,給webpack帶來很大的靈活性。

Loaders和Plugins經常被弄混,可是他們實際上是徹底不一樣的東西,能夠這麼來講,loaders是在打包構建過程當中用來處理源文件的(JSX,Scss,Less..),一次處理一個,Plugins並不直接操做單個文件,它直接對整個構建過程其做用

上面的實例中就使用了html-webpack-plugin插件,主要的功能就是自動引用使用的js文件,使用css的話,也會根據必定規則進行動態插入,在控制檯查看文件代碼時,能夠看到引用的css文件,會自動插在<head></head>之間。如截圖所示:
圖片描述

咱們能夠根據本身的項目構建方式,使用對應的插件,就不一一舉例說明了。

擴展-經常使用的Plugins清單

Plugins name 介紹
HtmlWebpackPlugin 簡單建立 HTML 文件,用於服務器訪問
clean-webpack-plugin 刪除指定的文件夾
webpack-bundle-analyzer webpack打包體積查看,便於優化文件體積
speed-measure-webpack-plugin 查看測量出在你的構建過程當中,每個 Loader 和 Plugin 的執行時長(優化webpack時能幫你看出對應的時間)

...更多優秀插件請查看清單連接

啓動靜態服務器

啓動一個靜態服務器,默認會自動刷新,就是說你對html,css,js文件作了修改並保存後,瀏覽器會默認刷新一次展示修改後的效果

正常狀況下咱們都是在開發環境中開發項目,因此以前配置的腳本"dev"能夠派上用場了,在執行npm run dev命令後,會啓動靜態服務器,咱們訪問localhost:3000端口就能夠看到開發的頁面內容了

對應的配置文件:

// webpack.config.js的配置文件
devServer: {
  host: 'localhost',  // 默認是localhost
  port: '3000',   // 端口
  open: true,    // 自動打開
  hot: true,    // 開啓熱更新
  openPage: 'assemble'  // 默認打開的文件
}

// package.json中的配置
"scripts": {
  "dev": "webpack-dev-server --open"
}

思考:熱更新和自動更新的區別??(待補充...)

開發、測試、上線構建的細微區別

一般本地開發,測試和線上的構建方式略微有點區別,線上文件都會將文件中的空行,空格,換行清除,而且壓縮html,css,js和對應image的體積,這樣就能保證體積最小,加快頁面的加載速度。

可是開發和測試環境一般,在瀏覽器中,沒法對代碼逐行打斷點進行調試,全部須要使用source maps進行調試,它使得咱們在瀏覽器中能夠看到源代碼,進而逐行打斷點調試。

使用source maps方法

在webpack.config.js文件中,添加devtool屬性,賦值爲 source-map或者inline-source-map便可,後者報錯信息更加具體,會指示源代碼中的具體錯誤位置,而source-map選項沒法指示到源代碼中的具體位置。

webpack優化

1. 代碼編寫過程當中遇到的現象

問題描述:更改一個文件,致使全部的文件都會從新進行編譯。

  • 修改前:
    圖片描述
  • 修改後:
    圖片描述

優化方案:使用緩存

  1. 安裝cache-loader模塊 npm install cache-loader -D
  2. 在module.rules對應的loader最前面添加cache-loader

參考文章

淺入淺出webpack

webpack 從入門到放棄(一)

入門 Webpack,看這篇就夠了

相關文章
相關標籤/搜索