前端面試之webpack篇

B_Cornelius發表於2017-09-27

還是以前一樣,有些概念面試可能會考,我都用*標記了出來,兩句話就總結清楚其餘的地方如果你想了解webpack,就仔細看看,雖然本教程不能讓你webpack玩的很6,但是懂操作流程夠了。面試你一般問你webpack的原理,Loader的原理,你有用那些優化措施
要是覺得對你有所幫助,請幫我點一個stargithub.com/skychenbo
前端開發已經模組化,它改進了程式碼庫的封裝和結構。打包工具已經成為了一個專案必不可少的部分,
如今這兒有幾種可能的選擇,例如webpack,grunt,gulp等。
webpack因為他的功能和擴充套件性在過去的幾年中,受到非常大的歡迎。但是webpack的配置總是讓人覺得很困惑,
今天我們將從一個空的配置檔案逐步完成一個完整的設定進行打包檔案。

概念

不像大多數的模組打包機,webpack是收把專案當作一個整體,通過一個給定的的主檔案,webpack將從這個檔案開始找到你的專案的所有依賴檔案,使用loaders處理它們,最後打包成一個或多個瀏覽器可識別的js檔案

install

首先新增我們即將使用的包:

npm install webpack webpack-dev-server --save-dev複製程式碼

webpack是我們需要的模組打包機,webpack-dev-server用來建立本地伺服器,監聽你的程式碼修改,並自動重新整理修改後的結果。這些是有關devServer的配置

contentBase,  // 為檔案提供本地伺服器
port, // 監聽埠,預設8080
inline, // 設定為true,原始檔發生改變自動重新整理頁面
historyApiFallback  // 依賴HTML5 history API,如果設定為true,所有的頁面跳轉指向index.html
devServer:{
    contentBase: './src' // 本地伺服器所載入的頁面所在的目錄
    historyApiFallback: true, // 不跳轉
    inline: true // 實時重新整理
}
然後我們在根目錄下建立一個'webpack.config.js',在'package.json'新增兩個命令用於本地開發和生產釋出


"scripts": {
            "start": "webpack-dev-server",
            "build": "webpack"
        }複製程式碼

在使用webpack命令的時候,他將接受webpack的配置檔案,除非我們使用其他的操作

entry

entry: 用來寫入口檔案,它將是整個依賴關係的根

var baseConfig = {
        entry: './src/index.js'
    }複製程式碼

當我們需要多個入口檔案的時候,可以把entry寫成一個物件

var baseConfig = {
        entry: {
            main: './src/index.js'
        }
    }複製程式碼

我建議使用後面一種方法,因為他的規模會隨你的專案增大而變得繁瑣

output

output: 即使入口檔案有多個,但是隻有一個輸出配置

var path = require('path')
    var baseConfig = {
        entry: {
            main: './src/index.js'
        },
        output: {
            filename: 'main.js',
            path: path.resolve('./build')
        }
    }
    module.exports = baseConfig複製程式碼

如果你定義的入口檔案有多個,那麼我們需要使用佔位符來確保輸出檔案的唯一性

output: {
        filename: '[name].js',
        path: path.resolve('./build')
    }複製程式碼

如今這麼少的配置,就能夠讓你執行一個伺服器並在本地使用命令npm start或者npm run build來打包我們的程式碼進行釋出

Loader

loader的作用
1、實現對不同格式的檔案的處理,比如說將scss轉換為css,或者typescript轉化為js
2、轉換這些檔案,從而使其能夠被新增到依賴圖中
loader是webpack最重要的部分之一,通過使用不同的Loader,我們能夠呼叫外部的指令碼或者工具,實現對不同格式檔案的處理,loader需要在webpack.config.js裡邊單獨用module進行配置,配置如下:

test: 匹配所處理檔案的副檔名的正規表示式(必須)
    loader: loader的名稱(必須)
    include/exclude: 手動新增處理的檔案,遮蔽不需要處理的檔案(可選)
    query: 為loaders提供額外的設定選項
    ex: 
        var baseConfig = {
            // ...
            module: {
                rules: [
                    {
                        test: /*匹配檔案字尾名的正則*/,
                        use: [
                            loader: /*loader名字*/,
                            query: /*額外配置*/
                        ]
                    }
                ]
            }
        }複製程式碼

要是loader工作,我們需要一個正規表示式來標識我們要修改的檔案,然後有一個陣列表示
我們表示我們即將使用的Loader,當然我們需要的loader需要通過npm 進行安裝。例如我們需要解析less的檔案,那麼webpack.config.js的配置如下:

var baseConfig = {
                entry: {
                    main: './src/index.js'
                },
                output: {
                    filename: '[name].js',
                    path: path.resolve('./build')
                },
                devServer: {
                    contentBase: './src',
                    historyApiFallBack: true,
                    inline: true
                },
                module: {
                    rules: [
                        {
                            test: /\.less$/,
                            use: [
                                {loader: 'style-loader'},
                                {loader: 'css-loader'},
                                {loader: 'less-loader'}
                            ],
                            exclude: /node_modules/
                        }
                    ]
                }
            }複製程式碼

這裡介紹幾個常用的loader:
babel-loader: 讓下一代的js檔案轉換成現代瀏覽器能夠支援的JS檔案。
babel有些複雜,所以大多數都會新建一個.babelrc進行配置
css-loader,style-loader:兩個建議配合使用,用來解析css檔案,能夠解釋@import,url()如果需要解析less就在後面加一個less-loader
file-loader: 生成的檔名就是檔案內容的MD5雜湊值並會保留所引用資源的原始副檔名
url-loader: 功能類似 file-loader,但是檔案大小低於指定的限制時,可以返回一個DataURL事實上,在使用less,scss,stylus這些的時候,npm會提示你差什麼外掛,差什麼,你就安上就行了

Plugins

plugins和loader很容易搞混,說都是外部引用有什麼區別呢? 事實上他們是兩個完全不同的東西。這麼說loaders負責的是處理原始檔的如css、jsx,一次處理一個檔案。而plugins並不是直接操作單個檔案,它直接對整個構建過程起作用下面列舉了一些我們常用的plugins和他的用法
ExtractTextWebpackPlugin: 它會將入口中引用css檔案,都打包都獨立的css檔案中,而不是內嵌在js打包檔案中。下面是他的應用

var ExtractTextPlugin = require('extract-text-webpack-plugin')
        var lessRules = {
            use: [
                {loader: 'css-loader'},
                {loader: 'less-loader'}
            ]
        }

        var baseConfig = {
            // ... 
            module: {
                rules: [
                    // ...
                    {test: /\.less$/, use: ExtractTextPlugin.extract(lessRules)}
                ]
            },
            plugins: [
                new ExtractTextPlugin('main.css')
            ]
        }複製程式碼

HtmlWebpackPlugin:
作用: 依據一個簡單的index.html模版,生成一個自動引用你打包後的js檔案的新index.html

var HTMLWebpackPlugin = require('html-webpack-plugin')
            var baseConfig = {
                // ...
                plugins: [
                    new HTMLWebpackPlugin()
                ]
            }複製程式碼

HotModuleReplacementPlugin: 它允許你在修改元件程式碼時,自動重新整理實時預覽修改後的結果注意永遠不要在生產環境中使用HMR。這兒說一下一般情況分為開發環境,測試環境,生產環境。
用法如 new webpack.HotModuleReplacementPlugin()
webapck.config.js的全部內容

const webpack = require("webpack")
        const HtmlWebpackPlugin = require("html-webpack-plugin")
        var ExtractTextPlugin = require('extract-text-webpack-plugin')
        var lessRules = {
            use: [
                {loader: 'css-loader'},
                {loader: 'less-loader'}
            ]
        }
        module.exports = {
            entry: {
                    main: './src/index.js'
                },
                output: {
                    filename: '[name].js',
                    path: path.resolve('./build')
                },
                devServer: {
                    contentBase: '/src',
                    historyApiFallback: true,
                    inline: true,
                    hot: true
                },
                module: {
                    rules: [
                        {test: /\.less$/, use: ExtractTextPlugin.extract(lessRules)}
                    ]
                },
                plugins: [
                new ExtractTextPlugin('main.css')
            ]
        }複製程式碼

產品階段的構建

目前為止,在開發階段的東西我們已經基本完成了。但是在產品階段,還需要對資源進行別的
處理,例如壓縮,優化,快取,分離css和js。首先我們來定義產品環境

var ENV = process.env.NODE_ENV
    var baseConfig = {
        // ... 
        plugins: [
            new webpack.DefinePlugin({
                'process.env.NODE_ENV': JSON.stringify(ENV)
            })
        ]
    }複製程式碼

然後還需要修改我們的script命令

"scripts": {
            "start": "NODE_ENV=development webpack-dev-server",
            "build": "NODE_ENV=production webpack"
        }複製程式碼

process.env.NODE_ENV 將被一個字串替代,它執行壓縮器排除那些不可到達的開發程式碼分支。
當你引入那些不會進行生產的程式碼,下面這個程式碼將非常有用。

if (process.env.NODE_ENV === 'development') {
            console.warn('這個警告會在生產階段消失')
        }複製程式碼

優化外掛

下面介紹幾個外掛用來優化程式碼
OccurenceOrderPlugin: 為元件分配ID,通過這個外掛webpack可以分析和優先考慮使用最多 的模組,然後為他們分配最小的ID
UglifyJsPlugin: 壓縮程式碼
下面是他們的使用方法
var baseConfig = {
// ...
new webpack.optimize.OccurenceOrderPlugin()
new webpack.optimize.UglifyJsPlugin()
}
然後在我們使用npm run build會發現程式碼是壓縮的

總結

webpack的配置檔案的複雜度,依賴於你專案的需要。小心的運用他們。因為隨著專案的增長,它們會變得很難馴服。內容有點多,事實上總結起來也不是特別多,也就Loader,plugins。其他的地方都比較簡單。這篇文章大概花了我三天的時間,網上看各種教程,然後看官網,真挺累的。這兒寫完我就去睡覺

相關文章