關於Webpack詳述系列文章 (第一篇)

WebPack官網地址(https://webpack-china.org/)

1. 什麼是WebPack

WebPack能夠看作是模塊打包機:它作的事情是,分析你的項目結構,找到JavaScript模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Scss,TypeScript等),並將其打包爲合適的格式以供瀏覽器使用。css

構建就是把源代碼轉換成發佈到線上的可執行 JavaScrip、CSS、HTML 代碼,包括以下內容。html

  • 代碼轉換:TypeScript 編譯成 JavaScript、SCSS 編譯成 CSS 等。
  • 文件優化:壓縮 JavaScript、CSS、HTML 代碼,壓縮合並圖片等。
  • 代碼分割:提取多個頁面的公共代碼、提取首屏不須要執行部分的代碼讓其異步加載。
  • 模塊合併:在採用模塊化的項目裏會有不少個模塊和文件,須要構建功能把模塊分類合併成一個文件。
  • 自動刷新:監聽本地源代碼的變化,自動從新構建、刷新瀏覽器。
  • 代碼校驗:在代碼被提交到倉庫前須要校驗代碼是否符合規範,以及單元測試是否經過。
  • 自動發佈:更新完代碼後,自動構建出線上發佈代碼並傳輸給發佈系統。

構建實際上是工程化、自動化思想在前端開發中的體現,把一系列流程用代碼去實現,讓代碼自動化地執行這一系列複雜的流程。 構建給前端開發注入了更大的活力,解放了咱們的生產力。前端

2. 初始化項目

mkdir webpack-start
cd webpack-start
npm init

3. 快速上手

3.1 webpack核心概念

  • Entry:入口,Webpack 執行構建的第一步將從 Entry 開始,可抽象成輸入。
  • Module:模塊,在 Webpack 裏一切皆模塊,一個模塊對應着一個文件。Webpack 會從配置的 Entry 開始遞歸找出全部依賴的模塊。
  • Chunk:代碼塊,一個 Chunk 由多個模塊組合而成,用於代碼合併與分割。
  • Loader:模塊轉換器,用於把模塊原內容按照需求轉換成新內容。
  • Plugin:擴展插件,在 Webpack 構建流程中的特定時機注入擴展邏輯來改變構建結果或作你想要的事情。
  • Output:輸出結果,在 Webpack 通過一系列處理並得出最終想要的代碼後輸出結果。

==>  Webpack 啓動後會從Entry裏配置的Module開始遞歸解析 Entry 依賴的全部 Module。 每找到一個 Module, 就會根據配置的Loader去找出對應的轉換規則,對 Module 進行轉換後,再解析出當前 Module 依賴的 Module。 這些模塊會以 Entry 爲單位進行分組,一個 Entry 和其全部依賴的 Module 被分到一個組也就是一個 Chunk。最後 Webpack 會把全部 Chunk 轉換成文件輸出。 在整個流程中 Webpack 會在恰當的時機執行 Plugin 裏定義的邏輯。node

3.2 配置webpack

npm install webpack webpack-cli -D
  • 建立src
  • 建立dist
    • 建立index.html
  • 配置文件webpack.config.js
  • 配置文件webpack.config.js
    • entry:配置入口文件的地址
    • output:配置出口文件的地址
    • module:配置模塊,主要用來配置不一樣文件的加載器
    • plugins:配置插件
    • devServer:配置開發服務器

4. 配置開發服務器

npm i webpack-dev-server –D
  • contentBase 配置開發服務運行時的文件根目錄
  • host:開發服務器監聽的主機地址
  • compress 開發服務器是否啓動gzip等壓縮
  • port:開發服務器監聽的端口
devServer:{
        contentBase:path.resolve(__dirname,'dist'),
        host:'localhost',
        compress:true,
        port:8080
}
"scripts": {
    "build": "webpack --mode development",
    "dev": "webpack-dev-server --open --mode development "
}

5. 支持加載css文件

5.1 什麼是Loader

經過使用不一樣的Loader,Webpack能夠要把不一樣的文件都轉成JS文件,好比CSS、ES6/七、JSX等react

  • test:匹配處理文件的擴展名的正則表達式
  • use:loader名稱,就是你要使用模塊的名稱
  • include/exclude:手動指定必須處理的文件夾或屏蔽不須要處理的文件夾
  • query:爲loaders提供額外的設置選項

loader三種寫法jquery

  • use
  • loader
  • use+loader

5.2 css-loader

npm i style-loader css-loader -D

配置加載器webpack

module: {
        rules:[
            {
                test:/\.css$/,
                use:['style-loader','css-loader'],
                include:path.join(__dirname,'./src'),
                exclude:/node_modules/
            }
        ]
   },

6. 自動產出html

咱們但願自動能產出HTML文件,並在裏面引入產出後的資源web

npm i html-webpack-plugin -D
  • minify 是對html文件進行壓縮,removeAttrubuteQuotes是去掉屬性的雙引號
  • hash 引入產出資源的時候加上哈希避免緩存
  • template 模版路徑
  plugins: [
        new HtmlWebpackPlugin({
       minify: {
            removeAttributeQuotes:true
        },
        hash: true,
        template: './src/index.html',
        filename:'index.html'
   })]

7. 支持圖片

7.1 手動添加圖片

npm i file-loader url-loader -D
  • file-loader 解決CSS等文件中的引入圖片路徑問題
  • url-loader 當圖片較小的時候會把圖片BASE64編碼,大於limit參數的時候仍是使用file-loader 進行拷貝
let logo=require('./images/logo.png');
let img=new Image();
img.src=logo;
document.body.appendChild(img);
{
    test:/\.(jpg|png|gif|svg)$/,
    use:'url-loader',
    include:path.join(__dirname,'./src'),
    exclude:/node_modules/
  }

7.2 在CSS中引入圖片

還能夠在CSS文件中引入圖片正則表達式

.img-bg{
    background: url(./images/logo.png);
    width:173px;
    height:66px;
}

8. 分離CSS

由於CSS的下載和JS能夠並行,當一個HTML文件很大的時候,咱們能夠把CSS單獨提取出來加載npm

npm install --save-dev extract-text-webpack-plugin@next
            {
                test:/\.css$/,
               use: ExtractTextWebpackPlugin.extract({
                    use:'css-loader'
                }),
                include:path.join(__dirname,'./src'),
                exclude:/node_modules/
            },

   plugins: [
        new ExtractTextWebpackPlugin('css/index.css'),        

處理圖片路徑問題

const PUBLIC_PATH='/';

output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
        publicPath:PUBLIC_PATH
    },

指定打包後的圖片位置

use: [
    {
     loader: 'url-loader',
     options: {
       limit: 1024,
      outputPath:'images/'
     }
    }
],

在HTML中使用圖片

npm i html-withimg-loader -D
<div class="img-container "><img src="./images/logo.png" alt="logo.png"></div>
  {
    test:/\.(html|html)$/,
    use:'html-withimg-loader',
    include:path.join(__dirname,'./src'),
    exclude:/node_modules/
 }

9. 編譯less 和 sass

npm i less less-loader -D
npm i node-saas sass-loader -D
@color:orange;
.less-container{
    border:1px solid @color;
}

$color:green;
.sass-container{
    border:1px solid $color;
}
const cssExtract=new ExtractTextWebpackPlugin('css.css');
const lessExtract=new ExtractTextWebpackPlugin('less.css');
const sassExtract=new ExtractTextWebpackPlugin('sass.css');

 {
                test:/\.less$/,
                use: lessExtract.extract({
                    use:['css-loader','less-loader']
                }),
                include:path.join(__dirname,'./src'),
                exclude:/node_modules/
            },
            {
                test:/\.scss$/,
                use: sassExtract.extract({
                    use:['css-loader','sass-loader']
                }),
                include:path.join(__dirname,'./src'),
                exclude:/node_modules/
            },

10. 處理CSS3屬性前綴

爲了瀏覽器的兼容性,有時候咱們必須加入-webkit,-ms,-o,-moz這些前綴

  • Trident內核:主要表明爲IE瀏覽器, 前綴爲-ms
  • Gecko內核:主要表明爲Firefox, 前綴爲-moz
  • Presto內核:主要表明爲Opera, 前綴爲-o
  • Webkit內核:產要表明爲Chrome和Safari, 前綴爲-webkit
npm i postcss-loader autoprefixer -D

postcss.config.js

module.exports={
    plugins:[require('autoprefixer')]
}
.circle {
    transform: translateX(100px);
}
{
                test:/\.css$/,
                use: cssExtract.extract({
                  use:['css-loader','postcss-loader']
                }),
                include:path.join(__dirname,'./src'),
                exclude:/node_modules/
            },

11. 轉義ES6/ES7/JSX

Babel實際上是一個編譯JavaScript的平臺,能夠把ES6/ES7,React的JSX轉義爲ES5

npm i babel-core babel-loader babel-preset-env babel-preset-stage-0 babel-preset-react -D
{
        test:/\.jsx?$/,
        use: {
            loader: 'babel-loader',
            options: {
                presets: ["env","stage-0","react"]
            }
        },
        include:path.join(__dirname,'./src'),
        exclude:/node_modules/
        },

12. 如何調試打包後的代碼

webapck經過配置能夠自動給咱們source maps文件,map文件是一種對應編譯文件和源文件的方法

  • source-map 把映射文件生成到單獨的文件,最完整最慢
  • cheap-module-source-map 在一個單獨的文件中產生一個不帶列映射的Map
  • eval-source-map 使用eval打包源文件模塊,在同一個文件中生成完整sourcemap
  • cheap-module-eval-source-map sourcemap和打包後的JS同行顯示,沒有映射列
devtool:'eval-source-map'

13.打包第三方類庫

13.1 直接引入

import _ from 'lodash';
alert(_.join(['a','b','c'],'@'));

13.2 插件引入

 new webpack.ProvidePlugin({
            _:'lodash'
 })

14. watch 

當代碼發生修改後能夠自動從新編譯

new webpack.BannerPlugin('珠峯培訓'),

 watch: true,
    watchOptions: {
        ignored: /node_modules/, //忽略不用監聽變動的目錄
        aggregateTimeout: 500, //防止重複保存頻繁從新編譯,500毫米內重複保存不打包
        poll:1000 //每秒詢問的文件變動的次數
    },

15. 拷貝靜態文件 

有時項目中沒有引用的文件也須要打包到目標目錄

npm i copy-webpack-plugin -D
 new CopyWebpackPlugin([{
            from: path.join(__dirname,'public'),//靜態資源目錄源地址
            to:'./public' //目標地址,相對於output的path目錄
        }]),

16. 打包前先清空輸出目錄

npm i  clean-webpack-plugin -D
new cleanWebpaclPlugin(path.join(__dirname,'dist'))

17. 壓縮JS

壓縮JS可讓輸出的JS文件體積更小、加載更快、流量更省,還有混淆代碼的加密功能

npm i uglifyjs-webpack-plugin -D
plugins: [
        new UglifyjsWebpackPlugin(),


]

18. 壓縮CSS

webpack能夠消除未使用的CSS,好比bootstrap中那些未使用的樣式

npm i -D purifycss-webpack purify-css
npm i bootstrap -S
{
                test:/\.css$/,
                use: cssExtract.extract({
                    use: [{
                         loader: 'css-loader',
                      options:{minimize:true}
                    },'postcss-loader']
                }),
            },
 new PurifyCSSPlugin({
             //purifycss根據這個路徑配置遍歷你的HTML文件,查找你使用的CSS
            paths:glob.sync(path.join(__dirname,'src/*.html'))
 }),

19. 服務器代理 

若是你有單獨的後端開發服務器 API,而且但願在同域名下發送 API 請求 ,那麼代理某些 URL 會頗有用。

//請求到 /api/users 如今會被代理到請求 http://localhost:9000/api/users。
        proxy: {
            "/api": "http://localhost:9000",
        }
 proxy: {
            "/api": {
                target: "http://localhost:9000",
                pathRewrite: {"^/api":""}
            }
}

20. resolve解析

20.1 extensions

指定extension以後能夠不用在require或是import的時候加文件擴展名,會依次嘗試添加擴展名進行匹配

 resolve: {
    //自動補全後綴,注意第一個必須是空字符串,後綴必定以點開頭
   extensions: ["",".js",".css",".json"],
 },

20.2 alias

配置別名能夠加快webpack查找模塊的速度

  • 每當引入jquery模塊的時候,它會直接引入jqueryPath,而不須要從node_modules文件夾中按模塊的查找規則查找
  • 不須要webpack去解析jquery.js文件
const bootstrap=path.join(__dirname,'node_modules/bootstrap/dist/css/bootstrap.css')
resolve: {
        alias: {
            'bootstrap': bootstrap
        }
    },

21. 區分環境變量

許多 library 將經過與 process.env.NODE_ENV 環境變量關聯,以決定 library 中應該引用哪些內容。例如,當不處於生產環境中時,某些 library 爲了使調試變得容易,可能會添加額外的日誌記錄(log)和測試(test)。其實,當使用 process.env.NODE_ENV === 'production' 時,一些 library 可能針對具體用戶的環境進行代碼優化,從而刪除或添加一些重要代碼。咱們能夠使用 webpack 內置的 DefinePlugin 爲全部的依賴定義這個變量:

npm install cross-env -D
"scripts": {
    "build": "cross-env NODE_ENV=production webpack --mode development",
     "dev": "webpack-dev-server --open --mode development "
  },
 plugins: [
        new webpack.DefinePlugin({
            NODE_ENV:JSON.stringify(process.env.NODE_ENV)
        }),
if (process.env.NODE_ENV == 'development') {
    console.log('這是開發環境');
} else {
    console.log('這是生產環境');
}

22. 暴露全局對象

require("expose-loader?libraryName!./file.js");
require("expose-loader?_!loadash");

let _=require('expose-loader?_!lodash');
{
               test: /^lodash$/,
               loader: "expose?_"
 }
setTimeout(function(){
    console.log(window._);
});

23. 多入口

有時候咱們的頁面能夠不止一個HTML頁面,會有多個頁面,因此就須要多入口

entry: {
        index: './src/index.js',
        main:'./src/main.js'
    },
     output: {
            path: path.resolve(__dirname, 'dist'),
            filename: '[name].[hash].js',
            publicPath:PUBLIC_PATH
        },
        new HtmlWebpackPlugin({
                    minify: {
                        removeAttributeQuotes:true
                    },
                    hash: true,
                    template: './src/index.html',
                    chunks:['index'],
                    filename:'index.html'
                }),
                new HtmlWebpackPlugin({
                    minify: {
                        removeAttributeQuotes:true
                    },
                    hash: true,
                    chunks:['main'],
                    template: './src/main.html',
                    filename:'main.html'
                })],

24. externals

若是咱們想引用一個庫,可是又不想讓webpack打包,而且又不影響咱們在程序中以CMD、AMD或者window/global全局等方式進行使用,那就能夠經過配置externals

 const $ = require("jquery");
 const $ = window.jQuery;
 externals: {
      jquery: "jQuery"//若是要在瀏覽器中運行,那麼不用添加什麼前綴,默認設置就是global
    },
相關文章
相關標籤/搜索