先後端分離之vue2.0+webpack2 實戰項目 -- webpack介紹

webpack的一點介紹

Webpack 把任何一個文件都當作一個模塊,模塊間能夠互相依賴(require or import),webpack 的功能是把相互依賴的文件打包在一塊兒。webpack 自己只能處理原生的 JavaScript 模塊,可是 loader 轉換器能夠將各類類型的資源轉換成 JavaScript 模塊。這樣,任何資源均可以成爲 Webpack 能夠處理的模塊。同時,webpack還有豐富的插件 plugin,能夠完成例如js,css的壓縮,公共依賴模塊的提取和注入,甚至利用模板對 html 進行動態拼接等功能。

同時,webpack 使用commonjs規範(require),支持es6語法(import)的編譯,能夠方便的抽離vue組件,這成爲咱們選擇它的重要理由。

 

對webpack工做方式直觀的理解(官網小示例)

import: es6 引入依賴的方式,還能夠用commonjs 規範的requirejavascript

var bar  = require('./bar')

module.exports: commonjs規範中對外暴露本模塊接口的方式。每一個模塊內部,都有一個module對象,表明當前模塊,module對象包含module.id,module.filename,module.exports等信息css

entry: 編譯的入口js文件,即須要處理的js文件(全部的其餘模塊包括image,css,vue組件,html模板等都是經過js依賴引入進來的)html

output: 編譯的出口js文件,即通過打包其餘資源、合併、壓縮等處理以後生成的js文件vue

本示例中由於 app.js 依賴 bar.js ,因此打包以後的 bundle.js 能夠理解爲app.js和bar.js合併後的jsjava

命令行工具中運行:wepack 即編譯成功node

 


 

實際項目中的webpack解析

本項目已支持功能

 1 對less編譯
 2 對js es6語法支持 3 編譯.vue組件,並自動內聯組件樣式 4 圖片打包,包括對html內圖片處理(利用html-loader和es6字符串模板),對小圖片生成base64 5 利用htmlWebpackPlugin動態拼接html 的公共部分和內容部分,引入相應css/js資源,並構建到指定目錄, 對ejs模板支持 6 對js內依賴的css分離並壓縮 7 對js引用的公共模塊抽取分離成單獨文件 8 區分開發環境和生產環境 9 js 壓縮 10 靜態文件(css/js/img)hash版本支持 11 清除目標文件目錄 12 eslint支持並實現自動修復部分問題 13 vue接口請求axios支持 14 熱更新,自動編譯並刷新瀏覽器

 

項目目錄結構

  |__ html
        |__ dist
              |__ income.html
              |__ index.html
        |__ src
              |__ income
                |__ income.ejs
                |__ income.js
              |__ index
                |__ index.ejs
                |__ index.js
              |__ layouts
                |__ footer.ejs
                |__ header.ejs
                |__ layout.ejs
                |__ layout.js
                |__ side-menu.e
                |__ top-nav.ejs
  |__ dist
        |__ css
        |__ img
        |__ js
              |__ income.js
              |__ index.js
              |__ manifest.js
              |__ vendors.js
  |__ src
        |__ css
        |__ img
        |__ js
              |__ component
                |__ App.vue
              |__ income.js
              |__ index.js
              |__ lib
                |__ axios.min.js
                |__ layer.js
                |__ vue.js
                |__ vue.min.js
  |__ mock
  |__ node_modules
  |__ webpack-config
        |__ .eslintrc.dev.js
        |__ .eslintrc.js
        |__ postcss.config.js
        |__ resolve.config.js
  |__ package.json
  |__ .babelrc
  |__ .eslintrc.js

 

一. entry介紹

var entries = getEntry('./src/**/*.js') // 得到入口js文件
entries.vendors = ['vue','axios']

module.exports = {
     /* 輸入文件 */
    entry: entries
}

一般咱們的項目中有大量的js入口文件,基本一個功能頁面有一個js,這時咱們的 entry 文件爲一個對象格式webpack

entries 爲:

{ income:
'./src/js/income.js', index: './src/js/index.js', vendors: [ 'vue', 'axios' ] }

key 值爲對應模塊的別名,webpack會依次處理這些模塊。ios

vendors 爲公共模塊,這裏咱們把vue, axios設置爲公共模塊,供下面進行提取公共模塊操做。git

 

之因此能夠直接寫vue, axios,是由於咱們在 alias 裏設置了別名:es6

var path = require('path')

module.exports = {
  // 模塊別名的配置,爲了使用方便,通常來講全部模塊都是要配置一下別名的
  alias: {
    'vue': path.resolve(__dirname, '../src/js/lib/vue.min.js'),
    'axios': path.resolve(__dirname, '../src/js/lib/axios.min.js')
  }
}

 

這裏的 path.resolve 做用是把相對路徑轉爲絕對路徑,假設我項目建在d:/demo 目錄下,

_dirname: d:\demo

path.resolve(__dirname, '../src/js/lib/vue.min.js'): d:\demo\src\js\lib\vue.min.js

 

getEntry() 爲獲取文件路徑的自定義函數:

/***** 獲取文件列表:輸出正確的js和html路徑 *****/
var glob = require('glob')

function getEntry(globPath) { var entries = {}, basename glob.sync(globPath).forEach(function (entry) { //排出layouts內的公共文件 if(entry.indexOf('layouts') == -1 && entry.indexOf('lib') == -1){ basename = path.basename(entry, path.extname(entry)) entries[basename] = entry } }) return entries }

一般webpack的entry入口文件,是功能性頁面的js,對於js庫等文件不須要列入入口文件進行處理。因此這裏對lib文件夾進行了排除。layouts文件夾爲獲取html路徑時須要排除的文件路徑。

 

二. output介紹

module.exports = {
    output: {
        /* 輸出目錄,沒有則新建 */
        path: path.resolve(__dirname, './dist'),
        /* 靜態目錄,能夠直接從這裏取文件 */
        publicPath: 'http://www.xxx.com/dist/',
        /* 文件名 */
        filename: 'js/[name].js?v=[chunkhash:8]'
    }
}

 publicPath: 若是有這項,則html中的引用的js路徑會加上publicPath,即 http://www.xxx.com/dist/js/[name].js?v=[chunkhash:8]

 filename: 這裏能夠自定義輸出後的文件名,加上版本號

  [name] :輸入模塊的別名

  [chunkhash] : 模塊的hash值,":8"表明保留8位hash值

  [hash] : 整個編譯環境的hash值

hash和chunkhash具體區別請看這裏

 

三. module介紹

loaders: webpack利用各類loader來把不一樣格式的文件封裝成模塊加載到js內,好比css-loader, vue-loader

特別注意:webpack v1 和webpack v2 的區別

module: {
- loaders: [ + rules: [ { test: /\.css$/, - loaders: [ - "style-loader", - "css-loader?modules=true" + use: [ + { + loader: "style-loader" + }, + { + loader: "css-loader", + options: { + modules: true + } + } ] }, { test: /\.jsx$/, loader: "babel-loader", // Do not use "use" here options: { // ... } } ] }

 

eslint-loader

module: {
    rules: [
           {
                test: /\.js$/,
                enforce: 'pre',
                loader: 'eslint-loader',
                include: path.resolve(__dirname, './src/js/**/*.js'),
                exclude: ['./src/js/lib','./src/js/component'],
                options: {
                    fix: true
                }
            }  
    ]          
}    

目的是 對js進行代碼風格和語法的校驗

enforce: 注意這是webpack v2的變更,v1是 preLoaders。設置爲pre表示對js的校驗在編譯以前進行,咱們只負責本身寫的js 語法和規範沒有問題便可,編譯後的代碼什麼樣都無論。

一般咱們只對本身寫的js進行校驗,類庫和包裏的js無需校驗。include即聲明咱們對哪些文件進行校驗,相反,exclude是排除校驗哪些文件。

fix:true 即在編譯時自動修復代碼風格和語法問題

 

babel-loader

{
    test: /\.js$/,
    loader: 'babel-loader',
    exclude: ['node_modules','./src/js/lib','./src/js/component']
}

es6語法目前不少瀏覽器不支持,咱們須要將其轉化爲大部分瀏覽器支持的es5語法,這就須要babel-loader

 

css-loader style-loader post-loader less-loader

{   
    test: /\.css$/, 
    use: ['style-loader', 'css-loader', 'postcss-loader']
},
{
    test: /\.less$/,
    use: ExtractTextPlugin.extract(['css-loader','postcss-loader','less-loader'])
}

對於有多個loader時,webpack v2也廢棄了v1的 " !" 鏈接,改成數組形式,且不能省略 " -loader " 以避免形成名稱混亂意思模糊,執行順序爲從右到左

postcss-loader爲集合處理css各類問題的平臺,其上面有各類插件來處理css,咱們這裏只用到了autoprefixer插件,後面插件部分會詳解

style-loader:能夠將css以style內聯方式嵌入到html頁面

ExtractTextPlugin:提取css, 後面插件部分會進行詳解

 

file-loader url-loader 處理圖片

{
    test: /\.(png|jpg|gif)$/,
    loader: 'url-loader?limit=5120&name=img/[name].[ext]?v=[hash:8]'
}

webpack中處理圖片用file-loader,但url-loader有個好處,它能夠把小圖片轉化成base64格式,其餘的大圖片再用file-loader處理,這裏的limit即爲臨界值,這裏定義小於5k圖片轉成base64格式,大於5k的用file-loader處理。

name: 能夠從新定義處理後的圖片並加上版本值。

 

 四. 插件plugin 

module: {},
plugins: [
        new ExtractTextPlugin('css/[name].css?v=[contenthash:6]'),
        new webpack.LoaderOptionsPlugin({
            options: {
                eslint: require( './webpack-config/.eslintrc.js'),
                postcss: require( './webpack-config/postcss.config.js')
            },
        })
    ]

 

插件能夠補充loader的功能,對其進行豐富完善,webpack聲明插件的方式能夠像上面的寫法也能夠以下方式:

module.exports.plugins.push(new htmlWebpackPlugin())

 亦或

module.exports.plugins = module.exports.plugins.concat([
        //壓縮css代碼
        new OptimizeCssAssetsPlugin({
            assetNameRegExp: /\.css/g,
            cssProcessor: require('cssnano'),
            cssProcessorOptions: { discardComments: {removeAll: true } },
            canPrint: true
        }),
        //壓縮JS代碼
        new webpack.optimize.UglifyJsPlugin({
            output: {
                comments: false, // 去掉註釋內容
            }
        })
    ])

一般後兩種寫法用於動態的使用插件。

 

extract-text-webpack-plugin 插件

默認狀況下,js依賴引入css,編譯後,css被加在js中,若是咱們想把css提取出一個單獨的文件,可使用這個插件,並能夠對提取出的css進行自定義命名和加版本hash值

income.js中依賴income.less

若是不使用extractTextPlugin,編譯後的目錄結構爲

查看income.js,發現css被引入在js之中,模塊id爲16

再看下webpack sourcemap下的income.less,css-loader已經將此文件編譯成對外暴露的模塊形式,模塊id爲16

使用extractTextPlugin插件後

income.js依賴的income.less被單獨提出,income.js中引入的模塊16發現提示 removed by extract-text-webpack-plugin,再看下此時的income.less

提示 removed by extract-text-webpack-plugin , 說明此插件已經順利的將js中的css提取成單文件形式

同時發現html中已插入income.css

這個是style-loader起的做用

 

LoaderOptionsPlugin插件

加載插件的配置項,好比eslint的語法配置,postcss的插件配置

 

optimize-css-assets-webpack-plugin 插件

壓縮css文件,對從js中提取出的css文件亦有效

注意:此插件是在css被提取出來加了hash值後進行處理,若是css文件提出來後被命名爲  css/[name].css?v=[contenthash:8] 形式,插件的使用以下

new OptimizeCssAssetsPlugin({
            assetNameRegExp: /\.css/g,  //注意不要寫成 /\.css$/g, 不然匹配不到css文件會致使壓縮不成功
            cssProcessor: require('cssnano'),
            cssProcessorOptions: { discardComments: {removeAll: true } },
            canPrint: true
        })

 

html-webpack-plugin 插件

 用於根據模板組合html各個部分,並插入對應引用的js,對先後端分離貢獻頗多,功能強大會有專門的篇章來介紹

 

 browser-sync-webpack-plugin 插件

熱更新,自動刷新瀏覽器

var BrowserSyncPlugin = require('browser-sync-webpack-plugin')

module.exports = {
    plugins: [
        new BrowserSyncPlugin({
            host: 'localhost',
            port: 3000,
            server: { baseDir: ['./'] }
        })
    ]
}

 

baseDir: localhost:3000 指定的目錄

結合webpack的watch,能夠作到實時編譯並刷新瀏覽器

只須要  webpack --watch  便可

 

CommonsChunkPlugin 插件

提取js的公共模塊,此插件爲webpack自帶的插件

// 提取公共模塊
new webpack.optimize.CommonsChunkPlugin({
    names:  ['vendors', 'manifest'], // 公共模塊的名稱
    //filename: 'js/[name]-[chunkhash:6].js', // 公共模塊的名稱
    chunks: 'vendors',  // chunks是須要提取的模塊
    minChunks: Infinity  //公共模塊最小被引用的次數
})

一般咱們的js可能會引入一些公共js文件,包括一些類庫,若是都打包在一個js中,這個js會變得很是龐大,並且一旦咱們功能頁面的js有變化,會致使打包後的js版本號進行更新而後從新加載,這個代價有些大,因此咱們會考慮把一些公共的js文件提取出一個單獨的文件,這樣在第一次訪問的時候會加載,以後就能夠緩存下來,減小服務器請求的壓力並提升加載速度。

names: 定義公共js模塊的文件名,即vendors.js,manifest是爲了存儲webpack編譯邏輯的一些信息,也會生成一個manifest.js並引入html。若是不生成manifest文件,這些webpack的編譯邏輯信息就會存儲在vendors中,當incomejs等頁面的功能js變化時,也會致使這個公共js的hash值變化,這樣又會致使從新加載100多k的vendor.js,這就失去了咱們提取公共模塊的意義。

而若是多生成一個manifest.js文件,會發現,當incomejs等頁面頁面功能js變化時,只有manifest.js的hash值有更新,vendors.js的hash值不變,雖然這樣會致使從新請求manifest.js但它的體積不過幾kb,代價遠小於vendorjs,因此咱們能夠用這種方式來優化咱們公共js模塊的加載方式。

 官網以下解釋,可供參考:

To extract the webpack bootstrap logic into a separate file, use the CommonsChunkPlugin on a name which is not defined as entry. Commonly the name manifest is used. See the code splitting libraries guide for details.
new webpack.optimize.CommonsChunkPlugin({ name: "manifest", minChunks: Infinity })

filename: 咱們能夠重命名公共模塊的文件名格式,此舉會覆蓋output中的文件名命名方式,不定義這個屬性默認用output中的filename方式

chunks:須要提取的模塊,在entry中咱們有以下定義  entries.vendors = ['vue','axios']  因此定義   chunks: 'vendors'  就是咱們會提取vuejs axiosjs到公共js中

minChunks: 公共模塊最小被引用的次數, 能夠寫成2,3...。Infinity: with more entries, this ensures that no other module goes into the vendor chunk,推薦用infinity

 

 CleanWebpackPlugin插件

 清除目標文件

new CleanWebpackPlugin(['dist'])

 

 

源碼:https://github.com/saysmy/vue2-webpack2-demo

若有錯誤請指正

 

html模板拼接詳解請見:先後端分離之vue2.0+webpack2 實戰項目 -- html模板拼接

 

轉載請註明出處 https://i.cnblogs.com/EditPosts.aspx?postid=6635504

相關文章
相關標籤/搜索