深入淺出webpack

第一章入門

1.1 前端的發(fā)展

1.1.1模塊化

模塊化是指將一個復(fù)雜的系統(tǒng)分解為多個模塊 以方便編碼
1、 CommonJS 是一種被廣泛使用的JavaScript 模塊化規(guī)范嗽桩,其核心思想是通過require方法來同步加載依賴的其他模塊浇冰,通過module.exports導(dǎo)出需要暴露的接口

  • 優(yōu)點(diǎn)
    • 代碼可復(fù)用于Node.js 環(huán)境下并運(yùn)行官硝,例如做同構(gòu)應(yīng)用(前后端通用的代碼)
    • 通過Npm 發(fā)布的很多第三方模塊都采用了CommonJS 規(guī)范
  • 缺點(diǎn)
    • 這樣的代碼無法直接運(yùn)行在瀏覽器環(huán)境下魄鸦,必須通過工具轉(zhuǎn)換成標(biāo)準(zhǔn)的ES5

2、 AMD 也是一種JavaScript模塊化規(guī)范贼急,與CommonJS 最大的不同在于,它采用了異步的方式去加載依賴的模塊捏萍。AMD規(guī)范主要用于解決針對瀏覽器環(huán)境的模塊化問題太抓,最具代表性的實現(xiàn)是requirejs,使用 define定義模塊照弥,使用require導(dǎo)入模塊

  • AMD優(yōu)點(diǎn)
    • 可在不轉(zhuǎn)換代碼的情況下直接在瀏覽器中運(yùn)行
    • 可異步加載依賴
    • 可并行加載多個依賴
    • 代碼可運(yùn)行在瀏覽器環(huán)境和Node.js環(huán)境下
  • AMD缺點(diǎn)
    • JavaScript 運(yùn)行環(huán)境沒有原生支持AMD腻异,需要先導(dǎo)入實現(xiàn)了AMD 的庫后才能正常使用

3、ES6 模塊化

  • ES6 模塊化是國際標(biāo)準(zhǔn)化組織ECMA 提出的JavaScript 模塊化規(guī)范这揣,它在語言層面上實現(xiàn)了模塊化悔常。瀏覽器廠商和Node都宣布要原生支持該規(guī)范。它將逐漸取代CommonJS 和AMD 規(guī)范给赞,成為瀏覽器和服務(wù)器通用的模塊解決方案机打。使用import導(dǎo)入模塊, export導(dǎo)出模塊
    • 缺點(diǎn)
      • 目前無法直接運(yùn)行在大部分JavaScript運(yùn)行環(huán)境下片迅,必須通過工具轉(zhuǎn)換成標(biāo)準(zhǔn)的ES5 后才能正常運(yùn)行

4残邀、樣式文件中的模塊化

1.1.2 新框架

  1. React
    React框架引入了JSX 語法到JavaScript 語言層面中,可以更靈活地控制視圖的渲染邏輯。
  2. Vue
    Vue ( https: //vuejs.org )框架將與一個組件相關(guān)的HTML模板芥挣、JavaScript 邏輯代碼驱闷、css樣式代碼都寫在一個文件里,這非常直觀空免。

3 . Angular2
Angular2 推崇采用Typescript 語言開發(fā)應(yīng)用空另,并且可以通過注解的語法描述組件的各種屬性。

1.1.3 新語言

  1. ES6
    ECMAScript 6.0(簡稱ES6 )是JavaScript 語言的下一代標(biāo)準(zhǔn)蹋砚。它在語言層面為JavaScript引入了很多新語法和API 扼菠,使得JavaScript 語言可以用來編寫復(fù)雜的大型應(yīng)用程序
  2. Typescript
    TypeScript 是JavaScript 的一個超集,由Microsoft 開發(fā)并開源坝咐,除了支持ES6 的所有功能循榆,還提供了靜態(tài)類型檢查
    3 . Flow
    Flow也是JavaScript 的一個超集,它的主要特點(diǎn)是為JavaScript 提供靜態(tài)類型檢查墨坚,和Typescript 相似但更靈活秧饮,可以讓我們只在需要的地方加上類型檢查。
    4 . scss
    SCSS ( http ://s ass-lang .com )可以讓我們用程序員的方式寫css 泽篮。它是一種css 預(yù)處理器浦楣,其基本思想是用和css 相似的編程語言寫完后再編譯成正常的css 文件。

1.2常見的構(gòu)建工具及對比

概述

構(gòu)建就是將源代碼轉(zhuǎn)換成可執(zhí)行的JavaScript 咪辱、css 振劳、html代碼,包括如下內(nèi)容油狂。

  • 代碼轉(zhuǎn)換:將TypeScript 編譯成JavaScript 历恐、將scss 編譯成css 等。
  • 文件優(yōu)化:壓縮JavaScript 专筷、css 弱贼、html代碼,壓縮合并圖片等磷蛹。
  • 代碼分割:提取多個頁面的公共代碼吮旅,提取首屏不需要執(zhí)行部分的代碼讓其異步加載。
  • 模塊合并:在采用模塊化的項目里會有很多個模塊和文件味咳,需要通過構(gòu)建功能將模塊分類合并成一個文件庇勃。
  • 自動刷新:監(jiān)昕本地源代碼的變化,自動重新構(gòu)建槽驶、刷新瀏覽器责嚷。
  • 代碼校驗:在代碼被提交到倉庫前需要校驗代碼是否符合規(guī)范,以及單元測試是否通過掂铐。
  • 自動發(fā)布:更新代碼后罕拂,自動構(gòu)建出線上發(fā)布代碼井傳輸給發(fā)布系統(tǒng)揍异。

構(gòu)建其實是工程化、自動化思想在前端開發(fā)中的體現(xiàn)爆班,將一系列流程用代碼去實現(xiàn)衷掷,讓代碼自動化地執(zhí)行這一系列復(fù)雜的流程。構(gòu)建為前端開發(fā)注入了更大的活力柿菩,解放了我們的生產(chǎn)力棍鳖。

常用的構(gòu)建工具

  • webpack、grunt碗旅、gulp、browserify镜悉、yeoman祟辟、FIS3、Rollup侣肄、Parcel

Webpack是一個打包模塊化JavaScript 的工具旧困,在Webpack 里一切文件皆模塊,通過Loader 轉(zhuǎn)換文件稼锅,通過Plugin 注入鉤子吼具,最后輸出由多個模塊組合成的文件。Webpack 專注于構(gòu)建模塊化項目矩距。

1.3安裝與使用

1.3.3 使用webpack

構(gòu)建一個最簡單的webpack項目步驟如下:

1拗盒、新建一個web項目
在node環(huán)境下,新建一個目錄锥债,再進(jìn)入項目根目錄陡蝇,初始化最簡單的采用了模塊化開發(fā)的項目

npm init -y

2、安裝webpack

npm i webpack@4.44 -D

運(yùn)行安裝在項目中的webpack哮肚,有以下兩種方式

  • 在項目根目錄下對應(yīng)的命令行里通過node rnodules/.bin/webpack 運(yùn)行
    Webpack 的可執(zhí)行文件
  • 在Npm Script 里定義的任務(wù)會優(yōu)先使用本項目下的Webpack登夫,在package.json文件中
scripts: {
  start: webpack --config webpack.config.js
}

3、實例:構(gòu)建一個采用了CommonJS 模塊化編寫的項目允趟,該項目中的某個網(wǎng)頁會通過JavaScript 顯示Hello Webpack 恼策。
詳見 F:\學(xué)習(xí)\webpack\allDemo\demo1.3.3

1.4使用Loader

1、在demo1.3.3項目中加入css文件
詳見 F:\學(xué)習(xí)\webpack\allDemo\demo1.4
2潮剪、步驟

  • 新建main.css
  • 將main.css引入main.js
require('./main.css)
  • 修改配置文件
 module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
  • 安裝style-loader,css-loader

1.5使用Plugin

1涣楷、在demo1.4項目中單獨(dú)提取css,并且對css進(jìn)行壓縮
詳見 F:\學(xué)習(xí)\webpack\allDemo\demo1.5
2抗碰、詳細(xì)步驟

  • 安裝單獨(dú)提取css的插件mini-css-extract-plugin和壓縮css文件插件optimize-css-assets-webpack-plugin
  • 修改配置文件
const miniCssExtractPlugin = require('mini-css-extract-plugin')
const optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
 module: {
        rules: [
            {
                test: /\.css$/,
                use: [miniCssExtractPlugin.loader, 'css-loader']
            }
        ]
    },
plugins: [
     new miniCssExtractPlugin(
            {
                filename: `./css/[name].css?v=[contenthash:4]`
            }
     ),
    new optimizeCssAssetsWebpackPlugin(
            {
            assetNameRegExp: /\.css(.*)$/,
            cssProcessor: require('cssnano'),
            cssProcessorOptions: {
              safe: true,
              discardComments: {
                removeAll: true
              }
            },
            canPrint: true
          }
        )
    ]

1.6使用DevServer

1总棵、步驟

  • 安裝webpack-dev-server
  • 啟動 webpack-dev-server --config webpack.config.js
  • 訪問localhost
    2、注意點(diǎn)
    webpack-dev-server與webpack-cli最新版不兼容改含,要安裝webpack-cli@3
    3情龄、配置模塊熱替換和source map
  • 模塊熱替換: 在不重新加載整個網(wǎng)頁的情況下,通過將被更新過的模塊替換老的模塊,再重新執(zhí)行一次來實現(xiàn)實時預(yù)覽
  • source Map:查看源碼
  • 具體配置
devtool: 'source-map', // 可選模式有七種骤视,常用source-map和eval-source-map
devServer: {
        hot: true
    }
  • 查看源碼:控制臺sources下面的webpack文件夾下面有個.文件夾中

第二章配置

2.1 entry

2.1.1 context

Webpack 在尋找相對路徑的文件時會以context 為根目錄鞍爱, context 默認(rèn)為執(zhí)行啟動Webpack 時所在的當(dāng)前工作目錄,通常為''专酗,也可以自定義

const path = require('path')
module.exports = {
    context: path.resolve(__dirname,'app'),
}

2.1.2 entry的類型

     // entry的屬性值可以是string\array\Object
    entry: './main.js'
    // array 類型睹逃,則搭配output.library 配置項使用時,只有數(shù)組里的最后一個入口文件的模塊會被導(dǎo)出
    entry: ['./main.js', './entry.js']
    // 配置多個入口祷肯,每個入口生成一個Chunk
    entry: {
        a: './entry1.js',
        b: './entry2.js',
        c: './entry3.js'
    }

2.1.3 chunk的名稱

Webpack 會為每個生成的Chunk 取一個名稱沉填, Chunk 的名稱和entry的配置有關(guān)。

  • 如果entry 是一個string 或array 佑笋,就只會生成一個Chunk 翼闹,這時Chunk 的名稱是main
  • 如果entry 是一個object ,就可能會出現(xiàn)多個Chunk 蒋纬,這時Chunk 的名稱是object 鍵值對中鍵的名稱猎荠。

2.2 output

output: {
        //filename 配置輸出文件的名稱,為string 類型
        filename: 'bundle.js' ,// 如果只有一個輸出文件蜀备,則可以將它寫成靜態(tài)不變的:
        filename: '[name].js',// 在有多個Chunk 要輸出時关摇,就需要借助模板和變量了,內(nèi)置變量有name\id\hash\chunkhash
        // chunkFilename用于指定在運(yùn)行過程中生成的Chunk 在輸出時的文件名稱
        chunkFilename:'common.js', 
        // path 配置輸出文件存放在本地的目錄碾阁,必須是string 類型的絕對路徑
        path: path.resolve(__dirname, 'dist'),
        // publicPath 配置發(fā)布到線上資源的URL 前綴
        publicPath: 'https://cdn.example.com/assets/',
        // libraryTarget 配置以何種方式導(dǎo)出庫,支持var/commonjs2/this/window/global
        libraryTarget: '',
        //library 配置導(dǎo)出庫的名稱
        library: 'LibraryName',
        // libraryExport 配置要導(dǎo)出的模塊中哪些子模塊需要被導(dǎo)出
        libraryExport: 'a'
    }

2.3 module

配置處理模塊的規(guī)則

 module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options:{
                            miniminze: true
                        },
                        /**
                         * 一組Loader 的執(zhí)行順序默認(rèn)是從右到左執(zhí)行的
                         * 通過enforce 選項可以將其中一個Loader 的執(zhí)行順序放到最前或者最后
                         * post的含義是將該Loader 的執(zhí)行順序放到最后
                         * pre代表將Loader 的執(zhí)行順序放到最前面
                         */
                        enforce: 'post'
                    }
                ],
                // 只命中src目錄里的JavaScript文件输虱,加快Webpack 的搜索速度
                include: path.resolve(__dirname, 'src'),
                // 排除node modules目錄下的文件
                exclude:path.resolve(__dirname, 'node modules')
            }
        ],
        /**
         * 1、noParse 配置項可以讓W(xué)ebpack 忽略對部分沒采用模塊化的文件的遞歸解析和處理
         * 這樣做的好處是能提高構(gòu)建性能
         * 2脂凶、noParse 是可選的配置項悼瓮,類型需要是RegExp 、[ RegExp )艰猬、fun ction 中的一種
         */
        noParse: /jquery|chartjs/,
        // parser 屬性可以更細(xì)粒度地配置哪些模塊語法被解析横堡、哪些不被解析
        parser: {
            amd: false, //禁用AMD
            commonjs : false, //禁用CommonJS
            system : false, //禁用SystemJS
            harmony : false, //禁用ES6 import/export
            requireinclude: false, //禁用require .in cl ude
            requireEnsure: false, //禁用require . ens ur e
            requireContext: false, //禁用require.context
            browserify: false, //禁用browserify
            requireJs : false, //禁用requirejs
        }
    }

2.4 resolve

Webpack 在啟動后會從配置的入口模塊出發(fā)找出所有依賴的模塊, Resolve 配置Webpack如何尋找模塊所對應(yīng)的文件冠桃。

resolve: {
        /**
         * alias 配置項通過別名來將原導(dǎo)入路徑映射成一個新的導(dǎo)入路徑
         * alias 還支持通過$符號來縮小范圍到只命中以關(guān)鍵字結(jié)尾的導(dǎo)入語句
         */
        alias: {
            components: './src/components/',
            'react$': '/path/react.min.js'
        },
        /**
         * 有一些第三方模塊會針對不同的環(huán)境提供幾份代碼
         * Webpack 會根據(jù)mainFields 的配置去決定優(yōu)先采用哪份代碼
         */
        mainFields: ['jsnext:main', 'browser', 'main'],
        /**
         * 在導(dǎo)入語句沒帶文件后綴時命贴, Webpack 會自動帶上后綴后去嘗試訪問文件是否存在。
         * resolve.extensions 用于配置在嘗試過程中用到的后綴列表            
         */
        extensions: ['.js', '.json'],
        // 配置Webpack 去哪些目錄下尋找第三方模塊食听,默認(rèn)只會去node modules 目錄下尋找
        modules: ['./ src/cornponents', 'node modules'],
        // 配置描述第三方模塊的文件名稱
        descriptionFiles: ['package.json'],
        // 是否所有的導(dǎo)入語句都帶后綴
        enforceExtension: false,
        // 功能與enforceExtension類似胸蛛,只對node_modules下的模塊生效,通常與enforceExtension配合使用
        enforceModuleExtension: false
    }

2.5 plugin

const miniCssExtractPlugin = require('mini-css-extract-plugin')
 plugins: [
        new miniCssExtractPlugin(
            {
                filename: `./css/[name].css?v=[contenthash:4]`
            }
        )   
    ]

2.6 Devserver

2.6.6 host

devServer.host 配置項用于配置DevServer 服務(wù)監(jiān)聽的地址樱报,只能通過命令行參數(shù)傳入葬项。例如紧阔,若想讓局域網(wǎng)中的其他設(shè)備訪問自己的本地服務(wù)侍匙,則可以在啟動Dev Server 時帶上--host 0.0.0 蒜撮。host 的默認(rèn)值是127.0.0.1 放航,即只有本地可以訪問Dev Server 的HTTP服務(wù)。

2.6.9 disableHostCheck

devServer.disableHostCheck 配置項用于配置是否關(guān)閉用于DNS 重新綁定的HTTP請求的HOST 檢查嚷量。
DevServer 默認(rèn)只接收來自本地的請求陋桂, 關(guān)閉后可以接收來自任意HOST的請求。
它通常用于搭配-- host 0.0.0 使用蝶溶, 因為想讓其他設(shè)備訪問自己的本地服務(wù)嗜历,但訪問時是直接通過IP 地址訪問而不是通過HOST 訪問,所以需要關(guān)閉HOST 檢查抖所。

  devServer: {
        hot: true,// 開啟模塊熱替換
        // inline 用于配置是否將這個代理客戶端自動注入將運(yùn)行在頁面中的Chunk 里梨州,默認(rèn)自動注入
        inline: true,
        // historyApiFallback用于方便地開發(fā)使用了HTML5 History API的單頁應(yīng)用
        historyApiFallback: true,
        // contentBase 配置DevServer HTTP 服務(wù)器的文件根目錄
        contentBase : path.join( __dirname,'public'),
        // headers 配置項可以在HTTP 響應(yīng)中注入一些HTTP 響應(yīng)頭
        headers: {
            'X-foo':  'bar'
        },
        // 端口號
        port: '8081',
        allowedHosts: [
            'host . com',
            'sub.host.com',
            // host2.com 和所有的子域名*.host2.com 都將匹配
            '.host2 . com'
        ],
        // 搭配--host 0.0.0使用
        disableHostCheck: true,
        // 使用https
        https: true,
        // 配置客戶端的日志等級,這會影響到我們在瀏覽器開發(fā)者工具控制臺里看到的日志內(nèi)容
        clientloglevel: 'warning',
        // compress 配置是否啟用Gzip 壓縮,為boolean 類型田轧,默認(rèn)為false
        compress: true,
        // open 用于在Dev Server 啟動且第一次構(gòu)建完時暴匠,自動用我們的系統(tǒng)的默認(rèn)瀏覽器去打開要開發(fā)的網(wǎng)頁
        open: true
    }

2.7 其他配置項

module.exports = {
   // target 配置項可以讓W(xué)ebpack 構(gòu)建出針對不同運(yùn)行環(huán)境的代碼,可選值:node/web/async-node/webworker/electron-main/electron-renderer
    target: 'node',
    devtool: 'source-map',
    watch: true,
    externals : {
        // 將導(dǎo)入語句里的jquery替換成運(yùn)行環(huán)境里的全局變量jQuery
        jquery: 'jQuery'
    },
    // ResolveLoader 用來告訴Webpack如何去尋找Loader
    resolveLoader: {
        // 去哪個目錄下尋找Loader
        modules: ['node modules'] ,
        // 入口文件的后綴
        extensions :['.js','. json'] ,
        // 指明入口文件位置的字段
        mainFields: ['loader','main']
    }
}

2.8 整體配置結(jié)構(gòu)

第三章實戰(zhàn)

3.1 使用ES6語言

概述

將es6轉(zhuǎn)換成es5做了以下兩件事情

  • 將新的ES6 語法用ES5 實現(xiàn)
  • 為新的API 注入polyfill(polyfill本意是聚酯纖維填充,這里用作補(bǔ)丁或者兼容插件講涯鲁,用來兼容原本一些不支持的屬性和方法)

3.1.3 認(rèn)識babel

在Babel 執(zhí)行編譯的過程中,會從項目根目錄下的.babelrc文件中讀取配置

/**
        1有序、presets屬性告訴Babel要轉(zhuǎn)換的源碼使用了哪些新的語法特性抹腿,一個Presets對一組
            新語法的特性提供了支持,多個Presets 可以疊加旭寿。Presets 其實是一組P lugins 的集合警绩,每個
            Plugin 完成一個新語法的轉(zhuǎn)換工作
        2、可選值: 
            1)  es2015/es2016/es2017/env(包含當(dāng)前所有ECMAScript 標(biāo)準(zhǔn)里的最新特性)
            2)  被社區(qū)提出來的但還未被寫入ECMAScript 標(biāo)準(zhǔn)里的特性: stage0/stage1/stage2/stage3/stage4
            3))用于支持一些特定應(yīng)用場景下的語法的特性盅称,和ECMAScript 標(biāo)準(zhǔn)沒有關(guān)系
    */
    "presets": [
        "env",
        [
            "es2015",
            {
                "modules": false
            }
        ],
        "stage-2",
        "react"
    ],
    /** 
       * plugins屬性告訴Babel要使用哪些插件肩祥,這些插件可以控制如何轉(zhuǎn)換代碼
    */
    "plugins": [
        [
            "transform-runtime", // Babel官方提供的一個插件,作用是減少冗余的代碼
            {
                "polyfill": false
            }
        ]
    ]
}

實現(xiàn)步驟

  1. 新建.babelrc文件缩膝,內(nèi)容如下
{
    "presets": ["env"]
}
  1. 安裝插件
  npm i -D babel-core@6 babel-loader@7 babel-preset-env

注釋:

  • babel-loader 8.x對應(yīng)babel-core 7.x
  • babel-loader 7.x對應(yīng)babel-core 6.x
  1. 通過loader接入Babel
module.exports = {
  module: {
      rules: [
        {
            test: /\.js$/,
            use: ['babel-loader'],
            exclude:path.resolve(__dirname, 'node modules')
        }
      ]  
}
}

3.4 使用sass

實現(xiàn)步驟

  1. 安裝loader
  npm i node-sass sass-loader@10 style-loader css-loader

注釋:sass-loader的版本不能太高混狠,依賴于node-sass
2.修改配置文件,增加loader配置

module: {
        rules: [
           ......
            {
                test: /\.scss/,
                use: ['style-loader', 'css-loader', 'sass-loader']
            }
          .......
        ]
    }

3.5 認(rèn)識PostCss

概述

PostCSS 是一個用 JavaScript 工具和插件轉(zhuǎn)換 CSS 代碼的工具疾层,和scss 的不同之處在于它可以通過插件機(jī)制靈活地擴(kuò)展其支持的特性将饺,而不像scss 那樣語法是固定的。PostCSS 的用處非常多痛黎,包括向css 自動加前綴予弧、使用下一代css 語法等

常用插件

  • postcss-import: 合并樣式表
  • postcss-url: 用于轉(zhuǎn)換 url ( ),inline 或者復(fù)制資產(chǎn)
  • cssnano : 壓縮代碼

使用步驟

1.安裝loader

npm i -D postcss-loader@4 style-loader css-loader

2.使用autoprefixer湖饱,需要在package.json中添加browserslist配置項

 "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]

3.安裝需要的插件掖蛤,以autoprefixer為例

npm i -D autoprefixer

4.兩種配置postcss的方案

  • 新建postcss.config.js,內(nèi)容如下
module.exports = {
    plugins: [
        [
            'autoprefixer'
        ]
    ]
}
  • 修改webpack.config.js配置項
    有postcss.config.js文件時
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader', 
                    'css-loader',
                    'postcss-loader'
                ]
            }
        ]
         
    }

沒有postcss.config.js文件時

rules: [
            {
                test: /\.css$/,
                use: [
                    'style-loader', 
                    {
                        loader: 'css-loader',
                        options: { importLoaders: 1 },
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            postcssOptions:{
                                plugins: [
                                    [
                                        'autoprefixer'
                                    ]
                                ]
                            }
                        }
                    }
                ]
            }
        ]

3.7 使用vue框架

步驟

1.安裝loader

npm i -S vue
npm i -D vue-loader css-loader vue-tamplate-compiler

2.配置webpack

  module: {
        rules: [
            {
                test: /\.vue$/,
                use: ['vue-loader']
            }
        ]
    }

3.實例:vue單文件組件使用方法如下
index.html

<body>
    <div id="app"></div>
    <script src="./dist/bundle.js"></script>
</body>

App.vue

<template>
    <h1>{{ msg }}</h1>
</template>
<script>
export default {
    data() {
        return {
            msg: 'Hello App'
        }
    }
}
</script>
<style>
h1 {
    color: red;
}
</style>

main.js

import Vue from 'vue'
import App from './App.vue'

new Vue({
    el: '#app',
    render: h => h(App)
})

3.9 為單頁應(yīng)用生成html

步驟

在上述實例中添加html-webpack-plugin
1.安裝

npm i html-webpack-plugin@4

注意:html-webpack-plugin最新版本不兼容webpack4
2井厌、修改配置文件

const HtmlPlugin = require('html-webpack-plugin')
 plugins: [
        new HtmlPlugin({
            filename: 'index.html',
            template: './template.html'
        })
    ]

3.13 構(gòu)建npm模塊

3.13.1 認(rèn)識npm

Npm (https://www.npmjs.com)是目前最大的JavaScript 模塊倉庫蚓庭,里面有全世界的開發(fā)者上傳的可復(fù)用模塊致讥。雖然在大多數(shù)情況下我們都是這些開放模塊的使用者,但我們也許會成為貢獻(xiàn)者彪置,會開發(fā)一個模塊上傳到Npm 倉庫拄踪。
發(fā)布到Npm 倉庫的模塊有以下幾個特點(diǎn):

  • 在每個模塊根目錄下都必須有一個描述該模塊的package.json 文件。該文件描述了模塊的入口文件是哪個拳魁,該模塊又依賴哪些模塊等
  • 模塊中的文件以JavaScript 文件為主惶桐,但不限于JavaScript 文件
  • 模塊中的代碼大多采用模塊化規(guī)范,,目前支持比較廣泛的是CommonJS 模塊化規(guī)范潘懊,上傳到Npm 倉庫的代碼最好遵守該規(guī)范姚糊。

3.14.2 認(rèn)識Service Workers

3.16 檢查代碼

3.16.1 代碼檢查具體是做什么的

3.16.2 怎么做代碼檢查

1 . 檢查JavaScript
ESlint C https: //eslint.org )
2、檢查Typescript
TSLint ( https://palantir.github . io/tslint/)
3.檢查css
style lint ( https://stylelint.io

3.16.3 結(jié)合Webpack 檢查代碼

1.eslint-loader ( https://github.com/MoOx/eslint-loader

module.exports = {
    module: {
        rules: [
              {
                  test: /\.js$/,
                   use: ['eslint-loader'],
 // 將eslint-loader 的執(zhí)行順序放在最前面授舟,防止其他Loader將處理后的代碼交給es lint-loader去檢查
                    enforce: 'pre'  
              }
         ]
    }
}

3.17 通過Node.js API 啟動Webpack

3.18 使用Webpack DevMiddleware

通過webpack-dev-middleware 能夠?qū)evServer 集成到現(xiàn)有的HTTP 服務(wù)器中救恨,讓現(xiàn)有的HTTP 服務(wù)器能返回Webpack構(gòu)建出的內(nèi)容,而不是在開發(fā)時啟動多個HTTP 服務(wù)器释树。這特別適用于后端接口服務(wù)采用Node.js 編寫的項目

3.19 加載圖片

步驟

1.安裝loader

npm i -D file-loader

2.修改配置文件

  {
                test: /\.png$/,
                use: [ {
                    loader: 'file-loader',
                    options: {
                        esModule: false
                    }
                }]
            }

或者使用url-loader(小圖)結(jié)合file-loader(大圖)

 {
                test: /\.png$/,
                use: [ {
                    loader: 'url-loader',
                    options: {
                        limit: 1024 * 30,
                        fallback: 'file-loader',
                        esModule: false
                    }
                }]
            }

3.21 加載Source Map

第四章優(yōu)化

概述

1.優(yōu)化開發(fā)體驗

  • 優(yōu)化構(gòu)建速度
  • 優(yōu)化使用體驗

2.優(yōu)化輸出質(zhì)量

  • 減少用戶感知到的加載時間
  • 提升流暢度

4.1 縮小文件的搜索范圍

4.1.1 優(yōu)化Loader 配置

在使用Loader 時肠槽,可以通過test 、include 奢啥、exclude 三個配置項來命中Loader 要應(yīng)用規(guī)則的文件

4 .1.2 優(yōu)化resolve.modules秸仙、resolve.mainFields、resolve.alias桩盲、resolve.extensions寂纪、module. noParse配置

 module.exports = {
      resolve : {
        // 使用絕對路徑指明第三方模塊存放的位置,以減少搜索步驟
          modules: [path.resolve( __dirname ,'node modules ')]赌结,
          mainFields: ['main'],
          alias: {
            'react': path.resolve( __dirname,’./nodemodules/react/dist/react.min.js ’),
          'src': path.resolve(__dirname, 'src')
          },
        extensions:[ '.js', '.json']
      }捞蛋,
    module: {
        noParse: [/react\.min\.js$/]
    }
}

4.2 使用DllPlugin

4.2.1 認(rèn)識DLL

以.dll為后綴名的文件,叫做動態(tài)鏈接庫柬姚,在一個動態(tài)鏈接庫中可以包含為其他模塊調(diào)用的函數(shù)和數(shù)據(jù)要給Web 項目構(gòu)建接入動態(tài)鏈接庫的思想拟杉,需要完成以下事情。

  • 將網(wǎng)頁依賴的基礎(chǔ)模塊抽離出來量承,打包到一個個單獨(dú)的動態(tài)鏈接庫中捣域,一個動態(tài)鏈接庫中可以包含多個模塊。
  • 當(dāng)需要導(dǎo)入的模塊存在于某個動態(tài)鏈接庫中時宴合,這個模塊不能被再次打包焕梅,而是去動態(tài)鏈接庫中獲取。
  • 頁面依賴的所有動態(tài)鏈接庫都需要被加載卦洽。

4.2.2 接入Webpack

Webpack 己經(jīng)內(nèi)置了對動態(tài)鏈接庫的支持贞言,需要通過以下兩個內(nèi)置的插件接入。

  • DllPlugin 插件: 用于打包出一個個單獨(dú)的動態(tài)鏈接庫文件
  • DllReferencePlugin 插件:用于在主要的配置文件中引入DllP!ugin 插件打包好的動態(tài)鏈接庫文件阀蒂。

具體實現(xiàn)方式

1.構(gòu)建出動態(tài)鏈接庫文件

const path = require('path')
const dllPlugin = require('webpack/lib/DllPlugin')
module.exports = {
    entry: {
        // 將React 相關(guān)的模塊放到一個單獨(dú)的動態(tài)鏈接庫中
        react: ['react', 'react-dom'],
        // 將項目需要所有的polyfill 放到一個單獨(dú)的動態(tài)鏈接庫中
        polyfill: ['core-js/fn/object/assign', 'core-js/fn/promise', 'whatwg-fetch']
    },
    output: {
        // 輸出的動態(tài)鏈接庫的文件名稱,[name]代表當(dāng)前動態(tài)鏈接庫的名稱
        filename: '[name].dll.js',
        path: path.resolve(__dirname, 'dist'),
        // 存放動態(tài)鏈接庫的全局變量名稱该窗,例如對于react 來說就是_dll_react,之所以在前面加上dll 弟蚀,是為了防止全局變量沖突
        library: '_dll_[name]'
    },
    plugins: [
        new dllPlugin({
            name: '_dll_[name]',
            path: path.join(__dirname, 'dist', '[name].manifest.json')
        })
    ]
}

2.使用動態(tài)鏈接庫文件

const path = require('path')
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin')
module.exports = {
    entry: {
        main: './main.js'
    },
    output: {
        // 輸出的動態(tài)鏈接庫的文件名稱,[name]代表當(dāng)前動態(tài)鏈接庫的名稱
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                use: ['babel-loader'],
                exclude: path.resolve(__dirname, 'node_modules')
            }
        ]
    },
    plugins: [
        new DllReferencePlugin({
            manifest: require('./dist/react.manifest.json')
        }),
        new DllReferencePlugin({
            manifest: require('./dist/polyfill.manifest.json')
        })
    ]
}

3.執(zhí)行構(gòu)建

  • 第一步
webpack --config webpack dll.config.js
  • 第二步:在確保動態(tài)鏈接庫存在時,才能正常編譯入口執(zhí)行文件酗失。方法是執(zhí)行webpack 命令

4.3.1 使用HappyPack

webpack自帶插件义钉,用于分解任務(wù)和管理線程

4.4 使用ParallelUglifyPlugin

概述

由于壓縮JavaScript 代碼時,需要先將代碼解析成用Object 抽象表示的AST 語法樹规肴,再去應(yīng)用各種規(guī)則分析和處理AST捶闸,所以導(dǎo)致這個過程的計算量巨大, 耗時非常多拖刃。

實現(xiàn)方式

當(dāng)Webpack 有多個JavaScript 文件需要輸出和壓縮時,原本會使用uglifyJS 去一個一個壓縮再輸出删壮,但是ParallelUglifyPlugin 會開啟多個子進(jìn)程,將對多個文件的壓縮工作分配給多個子進(jìn)程去完成兑牡,每個子進(jìn)程其實還是通過UglifyJS 去壓縮代碼央碟,但是變成了并行執(zhí)行。所以ParallelUglifyPlugin 能更快地完成對多個文件的壓縮工作均函。
注意:webpack4的js壓縮亿虽,設(shè)置mode或者使用terser-webpack-plugin插件

4.5 使用自動刷新

4.5. 1 文件監(jiān)昕

有以下兩種方式

  • 在webpack.config.js中設(shè)置watch:true
  • 使用命令webpack --watch

4.5.2 自動刷新瀏覽器

使用webpack-dev-server模塊去自動刷新頁面
在使用webpack-dev-server 模塊去啟動webpack 模塊時, webpack模塊的監(jiān)聽模式默認(rèn)會被開啟苞也。webpack 模塊會在文件發(fā)生變化時通知webpack-de v-server模塊洛勉。

1.自動刷新的原理

  • 借助瀏覽器擴(kuò)展去通過瀏覽器提供的接口刷新
  • 向要開發(fā)的網(wǎng)頁中注入代理客戶端代碼,通過代理客戶端去刷新整個頁面
  • 將要開發(fā)的網(wǎng)頁裝進(jìn)一個iframe 中墩朦,通過刷新iframe 去看到最新效果
    DevServer 支持第2 坯认、3 種方法翻擒, 第2 種是DevServer 默認(rèn)采用的刷新方法
  1. 優(yōu)化自動刷新的性能
    devServer.inline 配置項氓涣,它用來控制是否向Chunk 中注入代理客戶端,默認(rèn)會注入

4.6 開啟模塊熱替換

webpack-dev-server --hot

4.7 區(qū)分環(huán)境

module.exports = {
    plugins: [
         new webpack.DefinePlugin({
                'process.env': {
// 注意陋气,在定義環(huán)境變量的值時用JSON.stringify 包裹字符串的原因是劳吠,環(huán)境變量的值需要是一個由雙引號包裹的字符串,而JSON.stringify('production')的值正好等于'"pro duction "'
                      NODE_ENV: JSON.stringify ( 'production')
            }
        })
    ]
}

4.8 壓縮代碼

4.8.1壓縮js

optimization: {
        minimizer: [ // 用于配置 minimizers 和選項
            new UglifyJsPlugin({
                cache: true,
                parallel: true,
                sourceMap: true // set to true if you want JS source maps
            }),
            new OptimizeCSSAssetsPlugin({})
        ]
    }

4.8.2壓縮es6

4.8.3壓縮css

4.9CDN加速

4.9.1 什么是CDN

CDN(內(nèi)容分發(fā)網(wǎng)絡(luò))的作用就是加速網(wǎng)絡(luò)傳輸巩趁,通過將資源部署到世界各地痒玩,使用戶在訪問時按照就近原則從離其最近的服務(wù)器獲取資源,來加快資源的獲取速度议慰。CDN 其實是通過優(yōu)化物理鏈路層傳輸過程中的光速有限蠢古、丟包等問題來提升網(wǎng)速

4.9.2 接入CDN

要為網(wǎng)站接入CDN,需要將網(wǎng)頁的靜態(tài)資源上傳到CDN 服務(wù)上别凹,在服務(wù)這些靜態(tài)資源時需要通過CDN 服務(wù)提供的URL 地址去訪問草讶。
為了讓文件及時更新,成熟做法如下:

  • 針對HTML 文件:不開啟緩存炉菲,將HTML 放到自己的服務(wù)器上堕战,而不是CDN 服務(wù)上坤溃,同時關(guān)閉自己服務(wù)器上的緩存。自己的服務(wù)器只提供HTML 文件和數(shù)據(jù)接口
  • 針對靜態(tài)的JavaScript 嘱丢、css 薪介、圖片等文件:開啟CDN 和緩存,上傳到CDN 服務(wù)上越驻,同時為每個文件名帶上由文件內(nèi)容算出的Hash值汁政,例如上面的appa6976b6d.css 文件。帶上Hash值的原因是文件名會隨著文件的內(nèi)容而變化伐谈,只要文件的內(nèi)容發(fā)生變化烂完,其對應(yīng)的hash值也就會變化,它就會被重新下載诵棵,無論緩存時間有多長
    注意:
    1.對于瀏覽器限制:在同一時刻針對同一個域名的資源的并行請求有限制(大概4 個左右抠蚣,不同的瀏覽器可能不同),可以將靜態(tài)資源分散到不同的CDN 服務(wù)上
  1. 多域名解析會增加域名解析的時間履澳,解決方法是在HTML HEAD 標(biāo)簽中加入<link rel="dns-prefetch ” href = ”//js.cdn.com ”>預(yù)解析域名
    延遲嘶窄。

4.9.3 用Webpack 實現(xiàn)CDN的接入

構(gòu)建需要實現(xiàn)以下幾點(diǎn):

  • 靜態(tài)資源的導(dǎo)入URL需要變成指向CDN 服務(wù)的絕對路徑的URL,而不是相對于HTML 文件的URL
  • 靜態(tài)資源的文件名需要帶上由文件內(nèi)容算出來的Hash 值距贷,以防止被緩存
  • 將不同類型的資源放到不同域名的CDN 服務(wù)上柄冲,以防止資源的并行加載被阻塞

核心設(shè)置publicPath

  • 在output . publicPath 中設(shè)置JavaScript 的地址
  • 在css-loader.publicPath 中設(shè)置被css 導(dǎo)入的資源的地址
  • 在WebPlugin.stylePublicPath 中設(shè)置css 文件的地址

4.10 使用Tree Shaking

4 . 10.1 認(rèn)識Tree Shaking

Tree Shaking 可以用來剔除JavaScript 中用不上的死代碼,它依賴靜態(tài)的ES6 模塊化語法忠蝗,例如通過import 和export 導(dǎo)入现横、導(dǎo)出

4.10. 2 接入Tree Shaking

首先,為了將采用ES6 模塊化的代碼提交給Webpack 阁最,需要配置Babel 以讓其保留ES6模塊化語句戒祠。修改.babelrc 文件如下:

  {
    "presets": [
        [
            "env",
            {
                "modules": false  // 關(guān)閉Babel的模塊轉(zhuǎn)換功能,保留原有的ES6模塊化語法
            }
        ]
        
    ]
}

執(zhí)行命令

wabpack --display -used -exports --optimize-minimize

4.11 提取公共代碼

4 . 11.2 如何提取公共代碼

  • 根據(jù)網(wǎng)站所使用的技術(shù)攏速种,找出網(wǎng)站的所有頁面都需要用到的基礎(chǔ)庫姜盈,將它們提取到一個單獨(dú)的文件base.js 中,該文件包含了所有網(wǎng)頁的基礎(chǔ)運(yùn)行環(huán)境配阵。
  • 在剔除了各個頁面中被base.js 包含的部分代碼后馏颂, 再找出所有頁面都依賴的公共部分的代碼,將它們提取出來并放到common.js 中棋傍。
  • 再為每個網(wǎng)頁都生成一個單獨(dú)的文件救拉,在這個文件中不再包含base.js 和common.js 中包含的部分,而只包含各個頁面單獨(dú)需要的部分代碼瘫拣。
    注意:提取公共代碼webpack4使用vendors或者commons參數(shù)設(shè)置

4 .12 分割代碼以按需加載

在為單頁應(yīng)用做按需加載優(yōu)化時亿絮, 一般采用以下原則

  • 將整個網(wǎng)站劃分成一個個小功能,再按照每個功能的相關(guān)程度將它們分成幾類
  • 將每一類合并為一個Chunk ,按需加載對應(yīng)的Chunk
  • 按需加載用戶首次打開網(wǎng)站時需要看到的畫面所對應(yīng)的功能壹无,不要將其放到執(zhí)行入口所在的Chunk 中葱绒,以減少用戶能感知的網(wǎng)頁加載時間。
  • 對于不依賴大量代碼的功能點(diǎn)斗锭,例如依賴Cha rt.js 去畫圖表地淀、依賴flv .js 去播放視頻的功能點(diǎn),可再對其進(jìn)行按需加載岖是。

4.12.3 用Webpack 實現(xiàn)按需加載

import(/* webpackChunkName :”show " */ ’./show’) . then ((show) => {
    show ( ’ Webpack ’)
})

4.13 使用Prepack

4.13.1 認(rèn)識Prepack

Prepack 由Facebook 開源帮毁,采用了較為激進(jìn)的方法:在保持運(yùn)行結(jié)果一致的情況下,改變源代碼的運(yùn)行邏輯豺撑,輸出性能更好的JavaScript 代碼烈疚。實際上, Prepack 就是一個部分求值器聪轿,編譯代碼時提前將計算結(jié)果放到編譯后的代碼中爷肝, 而不是在代碼運(yùn)行時才去求值。
注意:暫時不推薦用于生產(chǎn)環(huán)境陆错,不成熟

4.14 開啟Scope Hoisting

4.14.1 認(rèn)識Scope Hoisting

Scop e Hoisting 可以讓W(xué)ebpack 打包出來的代碼文件更小灯抛、運(yùn)行更快,它又被譯作“作用域提升”音瓷,是在Webpack 3 中新推出的功能
webpack4的實現(xiàn)方法
https://www.cnblogs.com/cherryvenus/p/9808320.html

4.15 輸出分析

4.15.2webpack-bundle-analyzer

4.16 優(yōu)化總結(jié)

第五章原理

5.1 工作原理概括

5.1.1 基本概念

5.1.2 流程概括

5. 1.3 流程細(xì)節(jié)

5.2 輸出文件分析

5.3 編寫Loader

5.3.1 Loader 的職責(zé)

5.3.2 Loader 基礎(chǔ)

5.3.3 Loader 進(jìn)階

5.3.5 加載本地Loader

5.3.6 實戰(zhàn)

5.4 編寫Plugin

Webpack 通過Plugin 機(jī)制讓其更靈活对嚼,以適應(yīng)各種應(yīng)用場景。在webpack 運(yùn)行的生命周期中會廣播許多事件绳慎, Plugin 可以監(jiān)昕這些事件纵竖,在合適的時機(jī)通過Webpack 提供的API改變輸出結(jié)果。

5.4.4 實戰(zhàn)

5.5 調(diào)試Webpack

附錄

小技巧

1杏愤、vscode展開壓縮代碼
需要首先打開(ctrl+shift+p)命令行面板,選擇format selection with,
然后里面選擇Prettier -code formatter
2靡砌、linix命令

  • 刪除文件:rm 【文件名】
  • 新建文件: touch 【文件名】
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市声邦,隨后出現(xiàn)的幾起案子乏奥,更是在濱河造成了極大的恐慌摆舟,老刑警劉巖亥曹,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異恨诱,居然都是意外死亡媳瞪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門照宝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛇受,“玉大人,你說我怎么就攤上這事厕鹃【ぱ觯” “怎么了乍丈?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長把将。 經(jīng)常有香客問我轻专,道長,這世上最難降的妖魔是什么察蹲? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任请垛,我火速辦了婚禮,結(jié)果婚禮上洽议,老公的妹妹穿的比我還像新娘宗收。我一直安慰自己,他們只是感情好亚兄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布混稽。 她就那樣靜靜地躺著,像睡著了一般审胚。 火紅的嫁衣襯著肌膚如雪荚坞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天菲盾,我揣著相機(jī)與錄音颓影,去河邊找鬼。 笑死懒鉴,一個胖子當(dāng)著我的面吹牛诡挂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播临谱,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼璃俗,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了悉默?” 一聲冷哼從身側(cè)響起城豁,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抄课,沒想到半個月后唱星,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡跟磨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年间聊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抵拘。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡哎榴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尚蝌,我是刑警寧澤迎变,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站飘言,受9級特大地震影響氏豌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜热凹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一泵喘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧般妙,春花似錦纪铺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至苫拍,卻和暖如春芜繁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背绒极。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工骏令, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人垄提。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓榔袋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親铡俐。 傳聞我的和親對象是個殘疾皇子凰兑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容