webpack總結(jié)篇

博客鏈接 http://blog.poetries.top/2018/11/21/webpack-review/

關(guān)注公眾號(hào)獲取更多資訊

基于webpack3

一陡鹃、webpack簡(jiǎn)介

1.1 版本更迭

image.png

大版本變化

image.png

1.2 功能進(jìn)化

Webpack V1

  • 編譯、打包
  • HMR (模塊熱更新)
  • 代碼分割
  • 文件處理

Webpack V2

  • Tree Shaking
  • ES module
  • 動(dòng)態(tài) Import
  • 新的文檔

Webpack V3

  • Scope Hoisting (作用域提升)
  • Magic Comments (配合動(dòng)態(tài)import使用)

版本遷移

V1 -> V2

遷移指南 https://doc.webpack-china.org/guides/migrating/

V2 -> V3

更新升級(jí)即可

二匈仗、webpack核心概念

2.1 Entry

  • 代碼的入口
  • 打包的入口
  • 單個(gè)或多個(gè)

寫(xiě)法建議使用鍵值對(duì)寫(xiě)法

module.exports = {
  entry: 'index.js'
}
module.exports = {
  entry: '[index.js','vendor.js']
}
module.exports = {
  entry: {
      index:'index.js'
  }
}
module.exports = {
  entry: {
      index:['index.js','app.js'],
      vendor: 'vendor.js'
  }
}

2.2 Output

  • 打包成的文件(bundle)
  • 一個(gè)或多個(gè)
  • 自定義規(guī)則
  • 配合CDN
module.exports = {
  entry: 'index.js',
  output: {
      filename: 'index.min.js'
  }
}
module.exports = {
  entry: {
    index: 'index.js',
    vendor: 'vendor.js'
  },
  output: {
      filename: '[name].min[hash:5].js'
  }
}

2.3 Loaders

  • 處理文件
  • 轉(zhuǎn)化為模塊
module.exports = {
  module: {
      rules: [
        {
            test: /\.css$/,
            use: 'css-loader'
        }
      ]
  }
}

2.3.1 常用Loader

編譯相關(guān)

  • babel-loader
  • ts-loader

樣式相關(guān)

  • style-loader
  • css-loader
  • less-loader
  • postcss-loader

文件相關(guān)

  • file-loader
  • url-loader

2.4 Plugins

  • 參與打包整個(gè)過(guò)程
  • 打包優(yōu)化和壓縮
  • 配置編譯時(shí)的變量
  • 極其靈活
module.exports = {
 plugins: [
    new webpack.optimize.UglifyJsPlugin()
 ]
}

2.4.1 常用plugins

優(yōu)化相關(guān)

  • CommonsChunkPlugin
  • UglifyJsWebpackPlugin

功能相關(guān)

  • ExtractTextWebpackPlugin 提取css
  • HtmlWebpackPlugin 生成HTML模板
  • HotModuleReplacementPlugin 熱模塊替換
  • CopyWebpackPlugin 拷貝文件

2.5 名詞

  • Chunk 打包過(guò)程分割的代碼塊
  • Bundle 打包后的文件
  • Module

三熊楼、初探 webpack

3.1 使用babel打包es6

3.1.1 編譯 ES 6/7

Babel

npm install babel-loader@8.0.0-beta.0 @babel/core
npm install –save-dev babel-loader babel-core 

Babel Presets

主要有幾種類型選擇

  • es2015
  • es2016
  • es2017
  • env
  • babel-preset-react
  • babel-preset-stage 0 - 3
npm install @babel/preset-env –save-dev
npm install babel-preset-env –save-dev

Babel Polyfill

針對(duì)一些不能處理的函數(shù)方法(Generator燥撞、SetMap值漫、Array.from...)需要用到babel-Polyfill處理

  • 全局墊片
  • 為應(yīng)用準(zhǔn)備
npm install babel-polyfill –save
import “babel-polyfill”

Babel Runtime Transform

  • 局部墊片
  • 為開(kāi)發(fā)框架準(zhǔn)備
npm install babel-plugin-transform-runtime –save-dev

npm install babel-runtime –save

例子

module.exports = {
    entry: {
       app: 'app.js'
    },
    output: {
        filename: '[name].[hash:8].js'
    },
    module: {
        rules:[
            test: /\.js$/,
            use: {
                loader: 'babel-loader',
                options: {
                    presets: [
                        '@babel/preset-env',{
                            //指定target為根據(jù)哪些語(yǔ)法編譯
                            targets: {
                                browsers: ['> 1%','last 2 versions']
                            }
                        }
                    ]
                }
            },
            exclude: '/node_modules'
        ]
    }
}

對(duì)于webpackbabel的配置可以單獨(dú)提取處理.babelrc統(tǒng)一管理

{
    "presets": [
        ["@babel/preset-env",{
            targets: {
                browsers: ['> 1%','last 2 versions']
            }
        }]
    ],
    "plugins": [
      "transform-runtime"
    ]
]

3.2 打包 Typescript

npm i typescipt ts-loader  --save-dev
npm i typescipt awesome-typescript-loader  --save-dev

配置

  • tsconfig.json
  • webpack.config.js

tsconfig

  • 配置選項(xiàng):官網(wǎng)/docs/handbook/compiler-options.html
  • 常用選項(xiàng) compilerOptions include exclude

聲明文件

用于編譯時(shí)檢查錯(cuò)誤

loadsh為例伯诬,需要安裝@types/lodash帶有聲明文件的晚唇,而不是安裝lodash

npm install @types/lodash
npm install @types/vue

Typings

也可以這樣安裝帶有type的包

npm install typings
typings install lodash

例子

module.exports = {
    entry: {
        'app': 'app.js'
    },
    output: {
        filename: '[name].bundle.js'
    },
    module: {
        rules: [
            test: /\.tsx?$/,
            use: {
                loader: 'ts-loader'
            }
        ]
    }
}

在項(xiàng)目根目錄創(chuàng)建tsconfig.json

 {
    "compilerOptions": {
         "module": "comonjs",
         "target": "es5", //編譯后的文件在哪個(gè)環(huán)境運(yùn)行
         "allowJs": true,//允許js語(yǔ)法
    },
    "include": [
        //編譯路徑
        "./src/*"
    ],
    "exclude": [
        //排除編譯文件
        "./node_modules"
    ]
 }

3.3 提取 js 的公用代碼

  • 減少代碼冗余
  • 提高加載速度

主要使用內(nèi)置插件實(shí)現(xiàn)webpack.optimize.CommonsChunkPlugin

{
    plugins: [
         new webpack.optimize.CommonsChunkPlugin(option)
    ]
}

例子

module.exports = {
    entry: {
        "pageA": "./src/pageA",
        "pageB": "./src/pageB",
        "vendor": ['loash']//業(yè)務(wù)代碼和第三方代碼區(qū)分開(kāi),給loash單獨(dú)打一個(gè)包
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: '[name].bundle.js',
        chunkFilename: '[name].chunk.js'
    },
    plugins: [
    // 提取common
    new webpack.optimize.CommonsChunkPlugin({
         name: 'common',
         minChunks:2,//出現(xiàn)兩次就打包成common代碼
         chunks: ['pageA','pageB']//指定范圍提取公共代碼
     })
        
    // 提取vendor、取業(yè)務(wù)代碼manifest
     new webpack.optimize.CommonsChunkPlugin({
         //把entry的vendor代碼和這里的common(webpack打包的)代碼合并
         names: ['vendor','manifest']
         minChunks: Infinity
     })
     // ==== 提取業(yè)務(wù)代碼manifest== 合并到上面names中
     // 如果不想把webpack打包的代碼和vendor代碼合并 需要提取到manifest
     //new webpack.optimize.CommonsChunkPlugin({
         // webpack代碼和vendordiam區(qū)分開(kāi)
       //  name: 'manifest' //manifest即生成
       //  minChunks: Infinity
    // })
     
    ]
}
image.png

3.4 代碼分割和懶加載

第一種方式:通過(guò)wepack內(nèi)置方法

require.ensure動(dòng)態(tài)加載一個(gè)模塊盗似,接收四個(gè)參數(shù)

  • []:dependencies 初次并不會(huì)執(zhí)行
  • callback的時(shí)候才會(huì)執(zhí)行
  • errorCallback 可省略
  • chunkName

第二種方式:通過(guò)ES2015 Loader Spec

System.import()后面演變?yōu)?code>import()來(lái)動(dòng)態(tài)加載模塊

import()方式返回一個(gè)promiseimport中傳入需要依賴的明哩陕,動(dòng)態(tài)加載模塊,就可以像使用Promise一樣使用import().then()

代碼分割場(chǎng)景

  • 分離業(yè)務(wù)代碼 和 第三方依賴
  • 分離業(yè)務(wù)代碼 和 業(yè)務(wù)公共代碼 和 第三方依賴
  • 分離首次加載 和 訪問(wèn)后加載的代碼

例子

module.exports = {
    entry: {
        "pageA": "./src/pageA"
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        publicPath: './dist/',//動(dòng)態(tài)加載路徑
        filename: '[name].bundle.js',
        chunkFilename: '[name].chunk.js'
    }
}

目標(biāo)是提取pageA赫舒、pageB中公共的模塊moduleA

//src/pageA.js

import './subPageA'
import './subPageB'

//ensure的時(shí)候代碼不會(huì)執(zhí)行 需要在下面加載一次
require.ensure(['lodash'],function(){
    var _ = require('lodash')
    _.join([1,2,3])
},'vendor')// 指定chunk名稱


export default 'pageA'

運(yùn)行打包這時(shí)loadash提取到vendor

image.png

這時(shí)候還不是我們想要的

//src/pageA.js

require.include('./moduleA')

if(page === 'subPageA'){
  require.ensure(['./subPageA'],function(){
    var subPageA = require('./subPageA')
    },'subPageA')// 指定chunk名稱
}else{
  require.ensure(['./subPageB'],function(){
    var subPageB = require('./subPageB')
    },'subPageB')// 指定chunk名稱
}


//ensure的時(shí)候代碼不會(huì)執(zhí)行 需要在下面加載一次
require.ensure(['lodash'],function(){
    var _ = require('lodash')
    _.join([1,2,3])
},'vendor')// 指定chunk名稱


export default 'pageA'
image.png

這時(shí)候這有pageA中才有moduleA

image.png

新建一個(gè)html驗(yàn)證是否動(dòng)態(tài)加載

<html>
    <body>
        <script src="./dist/pageA.bundle.js"></script>
    </body>
</html>
image.png

import()動(dòng)態(tài)加載的寫(xiě)法

//src/pageA.js

require.include('./moduleA')

var page = 'subPageA'

if(page === 'subPageA'){
 // 指定chunkName /** webpackChunkName: 'subPageA' **/ 
  import(/** webpackChunkName: 'subPageA' **/,'./subPageA').then(function(subPageA){
      console.log(subPageA)
  })
}else{
  import(/** webpackChunkName: 'subPageB' **/'./subPageB').then(function(subPageB){
      console.log(subPageB)
  })
}

// 異步加載lodash
//ensure的時(shí)候代碼不會(huì)執(zhí)行 需要在下面加載一次
require.ensure(['lodash'],function(){
    var _ = require('lodash')
    _.join([1,2,3])
},'vendor')// 指定chunk名稱


export default 'pageA'

如果/** webpackChunkName: 'subPageA' **/相同悍及,則會(huì)合并處理

合并了subPageAsubPageB

image.png

來(lái)看看打包后的文件,既有A接癌、B

image.png

webpack代碼分割中使用async異步加載

module.exports = {
    entry: {
        "pageA": "./src/pageA",
        "pageB": "./src/pageB",
        "vendor": ['loash']//業(yè)務(wù)代碼和第三方代碼區(qū)分開(kāi),給loash單獨(dú)打一個(gè)包
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: '[name].bundle.js',
        chunkFilename: '[name].chunk.js'
    },
    plugins: [
    // add 異步模塊
    new webpack.optimize.CommonsChunkPlugin({
        aysnc:'async-common',//異步共同的東西
        children: true,
        names: ['vendor','manifest']
        minChunks: Infinity
    })
     
     
    // 提取vendor心赶、取業(yè)務(wù)代碼manifest
     new webpack.optimize.CommonsChunkPlugin({
         //把entry的vendor代碼和這里的common(webpack打包的)代碼合并
         names: ['vendor','manifest']
         minChunks: Infinity
     })
     
    ]
}
//src/subPageA.js


import './moduleA'

console.log('this. is subPageA')

export default 'subPageA'
//src/subPageB.js


import './moduleA'

console.log('this. is subPageB')

export default 'subPageB'
//src/subPageB.js


import './moduleA'

console.log('this. is moduleA')

export default 'moduleA'
//src/pageA.js

// 異步加載不能include 否則會(huì)和pageA打包到一起
// require.include('./moduleA')

import _ from 'lodash'

var page = 'subPageA'

if(page === 'subPageA'){
 // 指定chunkName /** webpackChunkName: 'subPageA' **/ 
  import(/** webpackChunkName: 'subPageA' **/,'./subPageA').then(function(subPageA){
      console.log(subPageA)
  })
}else{
  import(/** webpackChunkName: 'subPageB' **/'./subPageB').then(function(subPageB){
      console.log(subPageB)
  })
}

// === lodash不在異步加載
//ensure的時(shí)候代碼不會(huì)執(zhí)行 需要在下面加載一次
//require.ensure(['lodash'],function(){
//    var _ = require('lodash')
//    _.join([1,2,3])
//},'vendor')// 指定chunk名稱


export default 'pageA'
//src/pageB.js

import _ from 'lodash'

var page = 'subPageB'

if(page === 'subPageA'){
 // 指定chunkName /** webpackChunkName: 'subPageA' **/ 
  import(/** webpackChunkName: 'subPageA' **/,'./subPageA').then(function(subPageA){
      console.log(subPageA)
  })
}else{
  import(/** webpackChunkName: 'subPageB' **/'./subPageB').then(function(subPageB){
      console.log(subPageB)
  })
}

// === lodash不在異步加載
//ensure的時(shí)候代碼不會(huì)執(zhí)行 需要在下面加載一次
//require.ensure(['lodash'],function(){
//    var _ = require('lodash')
//    _.join([1,2,3])
//},'vendor')// 指定chunk名稱


export default 'pageB'
image.png
image.png

這樣就把subpageAsubPageB共同依賴的moduleA異步提取出來(lái)

3.5 處理 CSS 和 CSS 模塊化

引入css

需要兩個(gè)loaderstyle-loader(創(chuàng)建標(biāo)簽到文檔流中)扔涧、css-loader(可以import一個(gè)樣式文件,使得在js中可以使用)

Style-Loader

style-loader除了本身,還有這幾個(gè)loader

  • style-loader/url 可以注入link標(biāo)簽到頁(yè)面
  • style-loader/useable 控制樣式是否插入到頁(yè)面中

Style-Loader的options

  • insertAt (插入位置)
  • insertInto (插入到dom
  • singleton (是否只使用一個(gè)style 標(biāo)簽)
  • transform (轉(zhuǎn)化枯夜,瀏覽器環(huán)境下弯汰,插入頁(yè)面前)

例子

module.exports = {
    entry: {
        app: './src/app.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: './dist/', //指定從項(xiàng)目中哪里引入資源 
        filename: '[name].bundle.js'
    },
    module: {
        // loader解析從后往前處理
        rules: [
            {
                test: /\.css$/,
                use: [
                    {
                        //loader: 'style-loader',
                        loader: 'style-loader/url', //使用這個(gè)可以往頁(yè)面注入link標(biāo)簽 而不是style,這個(gè)并不常用
                    },
                    {
                        //loader: 'css-loader',
                        loader: 'file-loader'//使用這個(gè)可以往頁(yè)面注入link標(biāo)簽 而不是style 這個(gè)并不常用
                    }
                ]
            }
        ]
    }
}

CSS-Loader

options

  • alias (解析的別名)
  • importLoader@import
  • Minimize (是否壓縮)
  • modules (啟用css-modules

CSS-Modules

localIdentName: '[path][name]__[local]--[hash:base64:5]'

例子

module.exports = {
    entry: {
        app: './src/app.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: './dist/', //指定從項(xiàng)目中哪里引入資源 
        filename: '[name].bundle.js'
    },
    module: {
        // loader解析從后往前處理
        rules: [
            {
                test: /\.css$/,
                use: [
                    {
                        loader: 'style-loader',
                        options: { 
                           //合并多個(gè)style為一個(gè)
                            singleton:true
                        }
                    },
                    {
                        loader: 'css-loader',
                        options: {
                           minimize:true,
                           modules: true,
                           // css模塊化
                           localIdentName: '[path][name]_[local]_[hash:base64:5]'
                        }
                    }
                ]
            }
        ]
    }
}

配置Less / Sass

npm install less-loader less  --save-dev
npm install sass-loader node-sass --save-dev

例子

module.exports = {
    entry: {
        app: './src/app.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: './dist/', //指定從項(xiàng)目中哪里引入資源 
        filename: '[name].bundle.js'
    },
    module: {
        // loader解析從后往前處理
        rules: [
            {
                test: /\.(css|less)$/,
                use: [
                    {
                        loader: 'style-loader',
                        options: { 
                           //合并多個(gè)style為一個(gè)
                            singleton:true
                        }
                    },
                    {
                        loader: 'css-loader',
                        options: {
                           minimize:true,
                           modules: true,
                           // css模塊化
                           localIdentName: '[path][name]_[local]_[hash:base64:5]'
                        }
                    },
                    {
                        loader: 'less-loader'
                    },
                    {
                        loader: 'sass-loader'
                    }
                ]
            }
        ]
    }
}

提取 CSS

  • extract-loader
  • ExtractTextWebpackPlugin

例子

module.exports = {
    entry: {
        app: './src/app.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: './dist/', //指定從項(xiàng)目中哪里引入資源 
        filename: '[name].bundle.js'
    },
    module: {
        // loader解析從后往前處理
        rules: [
            {
                test: /\.(css|less)$/,
                use:
                ExtractTextWebpackPlugin.extra({
                    // 提取css并不會(huì)自動(dòng)加入到文檔中,需要在HTML手動(dòng)加入css文件
                    fallback: {
                        loader: 'style-loader',
                        options: { 
                           //合并多個(gè)style為一個(gè)
                            singleton:true
                        }
                    },
                    // 處理css
                    use: [
                        {
                            loader: 'css-loader',
                            options: {
                               minimize:true,
                               modules: true,
                               // css模塊化
                               localIdentName: '[path][name]_[local]_[hash:base64:5]'
                        }
                        },
                        {
                            loader: 'less-loader'
                        },
                        {
                            loader: 'sass-loader'
                        }
                    ]
                })
            }
        ]
    },
    plugins: [
        new ExtractTextWebpackPlugin({
            filename: '[name].min.css',
            allChunks: false //指定提取css范圍湖雹,true所有import進(jìn)來(lái)的css
        })
    ]
}
image.png

3.6 PostCSS in Webpack

安裝

  • postcss
  • postcss-loader
  • Autoprefixer
  • cssnano
  • postcss-cssnext

例子

module.exports = {
    entry: {
        app: './src/app.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: './dist/', //指定從項(xiàng)目中哪里引入資源 
        filename: '[name].bundle.js'
    },
    module: {
        // loader解析從后往前處理
        rules: [
            {
                test: /\.(css|less)$/,
                use:
                ExtractTextWebpackPlugin.extra({
                    // 提取css并不會(huì)自動(dòng)加入到文檔中咏闪,需要在HTML手動(dòng)加入css文件
                    fallback: {
                        loader: 'style-loader',
                        options: { 
                           //合并多個(gè)style為一個(gè)
                            singleton:true
                        }
                    },
                    // 處理css
                    use: [
                        {
                            loader: 'css-loader',
                            options: {
                               minimize:true,
                               modules: true,
                               // css模塊化
                               localIdentName: '[path][name]_[local]_[hash:base64:5]'
                        }
                        },
                        {
                            loader: 'less-loader'
                        },
                        {
                            loader: 'sass-loader'
                        },
                        {
                            loader: 'postcss-loader',
                            options: {
                                ident: 'postcss',
                                plugins: [
                                    require('antoprefixer')()
                                ]
                            }
                        }
                    ]
                })
            }
        ]
    },
    plugins: [
        new ExtractTextWebpackPlugin({
            filename: '[name].min.css',
            allChunks: false //指定提取css范圍,true所有import進(jìn)來(lái)的css
        })
    ]
}

3.7 Tree shaking

3.7.1 JS Tree shaking

使用場(chǎng)景

  • 常規(guī)優(yōu)化
  • 引入第三方庫(kù)的某一個(gè)功能

例子

module.exports = {
    entry: {
        app: './src/app.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: './dist/', //指定從項(xiàng)目中哪里引入資源 
        filename: '[name].bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['env'],
                            plugins: [
                                // lodash Tree shaking
                                'lodash'
                            ]
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new ExtractTextWebpackPlugin({
            filename: '[name].min.css',
            allChunks: false //指定提取css范圍摔吏,true所有import進(jìn)來(lái)的css
        })
        // Tree shaking
        new webpack.optimize.UglifyJsPlugin({
            
        })
    ]
}

有些庫(kù)不是es模塊寫(xiě)的鸽嫂,并不能tree shaking。需要借助其他工具

npm i babel-loader babel-core babel-preset-env babel-plugin-lodash --save

lodash Tree不生效

  • lodash-es --> no
  • babel-lugin-lodash --->working

查看模塊是否Tree Shaking方式:去第三方庫(kù)index.js中看模塊書(shū)寫(xiě)方式是否是es

3.7.2 CSS Tree shaking

主要使用 purifycss-webpack

例子

const glob = require('glob-all')

module.exports = {
    entry: {
        app: './src/app.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: './dist/', //指定從項(xiàng)目中哪里引入資源 
        filename: '[name].bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['env'],
                            plugins: [
                                // lodash Tree shaking
                                'lodash'
                            ]
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new ExtractTextWebpackPlugin({
            filename: '[name].min.css',
            allChunks: false //指定提取css范圍征讲,true所有import進(jìn)來(lái)的css
        })
        
        // 放到ExtractTextWebpackPlugin后面
        new PurifyCss({
            paths: glob.sync([
                path.join(__dirname,'./*.html'),
                path.join(__dirnname,'./src/*.js')
            ])
        })
        
        // Tree shaking
        new webpack.optimize.UglifyJsPlugin({
            
        })
    ]
}

四据某、由淺入深Webpack

4.1 文件處理

4.1.1 圖片處理

  • css中引入圖片
  • 自動(dòng)合成雪碧圖
  • 壓縮圖片
  • Base64編碼

處理需要用到的loader

  • file-loader css中引入圖片
  • url-loader base64編碼
  • img-loader 壓縮圖片
  • postcss-sprites合成雪碧圖

4.1.2 處理雪碧圖、base64诗箍、壓縮圖片

module.exports = {
    module: {
         rules: [
            {
                test: /\.(css|less)$/,
                use:
                extractLess.extract({
                    // 提取css并不會(huì)自動(dòng)加入到文檔中癣籽,需要在HTML手動(dòng)加入css文件
                    fallback: {
                        loader: 'style-loader',
                        options: { 
                           //合并多個(gè)style為一個(gè)
                            singleton:true
                        }
                    },
                    // 處理css
                    use: [
                        {
                            loader: 'css-loader',
                            options: {
                               minimize:true,
                               modules: true,
                               // css模塊化
                               localIdentName: '[path][name]_[local]_[hash:base64:5]'
                        }
                        },
                        {
                            loader: 'less-loader'
                        },
                        {
                            loader: 'sass-loader'
                        },
                        {
                            loader: 'postcss-loader',
                            options: {
                                ident: 'postcss',
                                plugins: [
                                    // 合并雪碧圖
                                    require('postcss-sprites')({
                                        // 指定雪碧圖輸出路徑
                                        spritePath: 'dist/assets/imgs/sprites',
                                        retina: true // 處理蘋(píng)果高清retina 圖片命名需要 xx@2x.png,對(duì)應(yīng)的圖片的css大小設(shè)置也要減小一半 
                                    })
                                ]
                            }
                        }
                    ]
                })
            },
            {
                test: /\.(png|jpg|gif)$/,
                use:[
                    //{
                    //    loader: //'file-loader',//處理圖片
                    //    options: {
                    //       publicPath:'',// 使得圖片地址可以訪問(wèn)
                    //       outputPath: 'dist/'
                    //       useRelativePath:true
                        //}
                    
                    //}
                    // url-loader會(huì)把圖片轉(zhuǎn)成base64
                    {
                        loader: 'url-loader',
                        options: {
                            name: '[name].min.[ext]' //5kb內(nèi)會(huì)轉(zhuǎn)成base64 ,否則輸出圖片路徑
                            limit: 1000, 
                            publicPath:'',
                            outputPath: 'dist/',
                            useRelativePath:true
                        }
                    },
                    // 壓縮圖片
                    {
                        loader: 'img-loader',
                        options: {
                            pngquant: {
                                //圖片質(zhì)量
                                quality:80
                            }
                        }
                    },
                    
                ]
            }
        ]
    }
}

4.1.2 處理字體文件

  • file-loader
  • url-loader
module.exports = {
    module: {
         rules: [
            {
                test: /\.(css|less)$/,
                use:
                extractLess.extract({
                    // 提取css并不會(huì)自動(dòng)加入到文檔中,需要在HTML手動(dòng)加入css文件
                    fallback: {
                        loader: 'style-loader',
                        options: { 
                           //合并多個(gè)style為一個(gè)
                            singleton:true
                        }
                    },
                    // 處理css
                    use: [
                        {
                            loader: 'css-loader',
                            options: {
                               minimize:true,
                               modules: true,
                               // css模塊化
                               localIdentName: '[path][name]_[local]_[hash:base64:5]'
                        }
                        },
                        {
                            loader: 'less-loader'
                        },
                        {
                            loader: 'sass-loader'
                        },
                        {
                            loader: 'postcss-loader',
                            options: {
                                ident: 'postcss',
                                plugins: [
                                    // 合并雪碧圖
                                    require('postcss-sprites')({
                                        // 指定雪碧圖輸出路徑
                                        spritePath: 'dist/assets/imgs/sprites',
                                        retina: true // 處理蘋(píng)果高清retina 圖片命名需要 xx@2x.png,對(duì)應(yīng)的圖片的css大小設(shè)置也要減小一半 
                                    })
                                ]
                            }
                        }
                    ]
                })
            },
            {
                test: /\.(png|jpg|gif)$/,
                use:[
                    //{
                    //    loader: //'file-loader',//處理圖片
                    //    options: {
                    //       publicPath:'',// 使得圖片地址可以訪問(wèn)
                    //       outputPath: 'dist/'
                    //       useRelativePath:true
                        //}
                    
                    //}
                    // url-loader會(huì)把圖片轉(zhuǎn)成base64
                    {
                        loader: 'url-loader',
                        options: {
                            name: '[name].min.[ext]' //5kb內(nèi)會(huì)轉(zhuǎn)成base64 ,否則輸出圖片路徑
                            limit: 1000, 
                            publicPath:'',
                            outputPath: 'dist/',
                            useRelativePath:true
                        }
                    },
                    // 壓縮圖片
                    {
                        loader: 'img-loader',
                        options: {
                            pngquant: {
                                //圖片質(zhì)量
                                quality:80
                            }
                        }
                    },
                    // 處理字體文件
                    {
                        test: /\.(eot|woff2|woff|ttf|svg)$/,
                        use: [
                            {
                                loader:'url-loader',
                                options: {
                                    name: '[name].min.[ext]' //5kb內(nèi)會(huì)轉(zhuǎn)成base64 ,否則輸出圖片路徑
                                    limit: 5000, 
                                    publicPath:'',
                                    outputPath: 'dist/',
                                    useRelativePath:true
                                }
                            }
                        ]
                    }
                    
                ]
            }
        ]
    }
}

4.1.3 處理第三方 JS 庫(kù)

處理第三方庫(kù) 用到providePlugin滤祖、imports-loader

1.providePlugin

以引入jQuery為例

npm i jquery
module.exports = {
    plugins: [
        new webpack.ProvidePlugin({
            // 在全局注入jQuery變量
            $:'jquery'
        })
    ]
}

引入本地libs中的jQuery

module.exports = {
    resolve: {
        alias: {
            // $確切匹配 把jQuery這個(gè)關(guān)鍵字解析到某個(gè)目錄下
            jquery$:path.resolve(__dirname,'src/libs/jquery.min.js')
        }
    },
    plugins: [
        new webpack.ProvidePlugin({
            // 在全局注入jQuery變量
            $:'jquery'
        })
    ]
}

2.imports-loader

module.exports = {
    module:{
        rules:[
            {
                test:path.resolve(__dirname,'src/app.js'),
                use:[
                    {
                        loader: 'imports-loader',
                        options: {
                            $: 'jquery'
                        }
                    }
                ]
            }
        ]
    }
}

4.2 HTML in webpack(自動(dòng)生成HTML)

自動(dòng)生成HTML筷狼,把這個(gè)頁(yè)面需要的jscss插入到頁(yè)面中

4.2.1 生成 HTML

htmlWebpackPlugin

options

  • template
  • filename
  • minify 是否壓縮
  • chunks
  • inject 是否讓css匠童、js通過(guò)標(biāo)簽形式插入到頁(yè)面中
module.exports = {
    entry: {
        app: './src/app.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].bundle.js'
    },
    plugin:[
        new htmlWebpackPlugin({
            filename:'index.html', // 不傳默認(rèn)index.html
            template: './index.html',//傳入模板
            inject:true,//控制js\css是否插入到頁(yè)面
            minify: {
                collapseWhitespace:true //壓縮空格
            },
            chunks:['app']//指定chunks會(huì)把跟這個(gè)入口相關(guān)的chunks插入到頁(yè)面中
        })
    ]
}

4.2.2 HTML 中引入圖片

需要用到html-loader

html-loader

options

  • attrs: [img:src]
module.exports = {
    entry: {
        app: './src/app.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].bundle.js',
        publicPath:'/' //網(wǎng)站路徑為/ 圖片等資源引用不會(huì)發(fā)生錯(cuò)誤
    },
    module:{
        rules:[
            {
                loader: 'url-loader',
                options: {
                    name: '[name].min.[ext]' //5kb內(nèi)會(huì)轉(zhuǎn)成base64 ,否則輸出圖片路徑
                    limit: 1000, 
                    publicPath:'',
                    outputPath: 'assets/imgs/',
                    //useRelativePath:true // 這里不能使用這個(gè) 因?yàn)閳D片路徑在HTML中埂材、css中都存在,打包的時(shí)候圖片會(huì)放錯(cuò)地方汤求。需要用到絕對(duì)路徑俏险,在output指定publicPath:'/'
                }
            },
            // 處理HTML中的圖片引用路徑問(wèn)題
            {
                test: /\.html$/,
                use: [
                    {
                        loader: 'html-loader',
                        options: {
                            attrs: ['img:src','img:data-src']
                        }
                    }
                ]
            }
        ]
    }
}

require在HTML中引入圖片

<img src="${require('./public/imgs/xx.png)}" />

4.2.3 配合優(yōu)化

提前載入webpack加載代碼

  • inline-manifest-webpack-plugin
  • html-webpack-inline-chunk-plugin

建議使用 html-webpack-inline-chunk-plugin

npm i html-webpack-inline-chunk-plugin
var HTMLInlieChunk = require('html-webpack-inline-chunk-plugin')

module.exports = {
    entry: {
        app: './src/app.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].bundle.js',
        publicPath:'/'
    },
    plugin:[
        new htmlWebpackPlugin({
            filename:'index.html', // 不傳默認(rèn)index.html
            template: './index.html',//傳入模板
            inject:true,//控制js\css是否插入到頁(yè)面
            minify: {
                collapseWhitespace:true //壓縮空格
            },
            chunks:['app']//指定chunks會(huì)把跟這個(gè)入口相關(guān)的chunks插入到頁(yè)面中
        })
        new webpack.mdtimize.CommonsChunkPlugin({
            name: 'manifest'
        })
        new HTMLInlieChunk({
            inlineChunks: ['manifest'] //把webpack生成的manifest提取到HTML文件script中,減少請(qǐng)求
        })
    ]
}

五首昔、Webpack 環(huán)境配置

5.1 Webpack Watch Mode

webpack --watch

// 簡(jiǎn)寫(xiě)
webpack -w
//webpack.config.js

var webpack = require('wepback')
var PurifyWebpack = require('pruifycss-webpack')
var ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var CleanWebpack = require('clean-webpacl-plugin')

var path = require('path')
var glob = rquire('glob-all')//處理多個(gè)路徑

var extractLess = new ExtractTextWebpackPlugin({
    filename: 'css/[name]-bundle-[hash:5].css'
})

module.exports = {
    entry: {
        app: './src/app.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name]-bundle-[hash:5].js'
    },
    module:{
        rules: [
            {
                test: /\.(css|less)$/,
                use:
                extractLess.extract({
                    // 提取css并不會(huì)自動(dòng)加入到文檔中寡喝,需要在HTML手動(dòng)加入css文件
                    fallback: {
                        loader: 'style-loader',
                        options: { 
                           //合并多個(gè)style為一個(gè)
                            singleton:true
                        }
                    },
                    // 處理css
                    use: [
                        {
                            loader: 'css-loader',
                            options: {
                               minimize:true,
                               modules: true,
                               // css模塊化
                               localIdentName: '[path][name]_[local]_[hash:base64:5]'
                        }
                        },
                        {
                            loader: 'less-loader'
                        },
                        {
                            loader: 'sass-loader'
                        },
                        {
                            loader: 'postcss-loader',
                            options: {
                                ident: 'postcss',
                                plugins: [
                                    // 合并雪碧圖
                                    require('postcss-sprites')({
                                        // 指定雪碧圖輸出路徑
                                        spritePath: 'dist/assets/imgs/sprites',
                                        retina: true // 處理蘋(píng)果高清retina 圖片命名需要 xx@2x.png,對(duì)應(yīng)的圖片的css大小設(shè)置也要減小一半 
                                    })
                                ]
                            }
                        }
                    ]
                })
            }
        ]
    }
    plugin: [
        new CleanWebpack()
    ]
}

5.2 Webpack Dev Server

5.2.1 Dev Server

不能用來(lái)直接打包文件,Dev Server搭建本地開(kāi)發(fā)勒奇,文件存在內(nèi)存中

特性

  • live reloading
  • 路徑重定向
  • 支持HTTPS
  • 瀏覽器中顯示編譯錯(cuò)誤
  • 接口代理
  • 模塊熱更新

dev server

  • inline
  • contentBase
  • port
  • histApiFllback
  • https
  • proxy
  • hot
  • openpage
  • lazy
  • overlay 開(kāi)啟錯(cuò)誤遮罩

使用

"script"{
    // 啟動(dòng)
    "server": "webpack-dev-server --open" 
}
module.exports = {
    entry: {
        app: './src/app.js'
    },
    
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: '/',
        filename: '[name].[hash:5].js'
    },
    
    devServer: {
        port: 9001,
        // 輸入任意路徑都不會(huì)出現(xiàn)404 都會(huì)重定向
       // historyApiFallback: true
        historyApiFallback: {
            //從一個(gè)確定的url指向?qū)?yīng)的文件
            //rewrites: [
            //    {
            //        from: '/pages/a',// 可以寫(xiě)正則
           //         to: '/pages/a.html'
            //    }
            rewrites: [
                {
                    from: /^\/([a-zA-Z0-9]+\/?)([a-zA-Z0-9]+)/
                    to: function(context){
                        return '/' + context.match[1] + context.match[2] + '.html'
                    }
                }
            ]
            ]
        }
    }
}

5.2.2 proxy代理遠(yuǎn)程接口

  • 代理遠(yuǎn)程接口請(qǐng)求
  • http-proxy-middleware
  • devServer.proxy
module.exports = {
    entry: {
        app: './src/app.js'
    },
    
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: '/',
        filename: '[name].[hash:5].js'
    },
    
    devServer: {
        port: 9001,
        // 輸入任意路徑都不會(huì)出現(xiàn)404 都會(huì)重定向
       // historyApiFallback: true
        historyApiFallback: {
            //從一個(gè)確定的url指向?qū)?yīng)的文件
            //rewrites: [
            //    {
            //        from: '/pages/a',// 可以寫(xiě)正則
           //         to: '/pages/a.html'
            //    }
            rewrites: [
                {
                    from: /^\/([a-zA-Z0-9]+\/?)([a-zA-Z0-9]+)/
                    to: function(context){
                        return '/' + context.match[1] + context.match[2] + '.html'
                    }
                }
            ]
            ]
        },
        proxy: {
            '/api': {
                target: 'https://blog.poetries.top',//代理到服務(wù)器
                changeOrigin:true,
                logLevel: 'debug',
                // pathRewite: { },
                headers:{}// 請(qǐng)求頭
            }
        }
    }
}

5.2.3 模塊熱更新

  • 保持應(yīng)用的數(shù)據(jù)狀態(tài)

  • 節(jié)省調(diào)試時(shí)間

  • 不需要刷新

  • devServer.hot

  • webpack.HotModleReplacementPlugin

  • webpack.NamedModulesPlugin 看到模塊更新的路徑

Module Hot Reloading

  • module.hot
  • module.hot.accept
module.exports = {
    entry: {
        app: './src/app.js'
    },
    
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: '/',
        filename: '[name].[hash:5].js'
    },
    
    devServer: {
        port: 9001,
        // 輸入任意路徑都不會(huì)出現(xiàn)404 都會(huì)重定向
       // historyApiFallback: true
        historyApiFallback: {
            //從一個(gè)確定的url指向?qū)?yīng)的文件
            //rewrites: [
            //    {
            //        from: '/pages/a',// 可以寫(xiě)正則
           //         to: '/pages/a.html'
            //    }
            rewrites: [
                {
                    from: /^\/([a-zA-Z0-9]+\/?)([a-zA-Z0-9]+)/
                    to: function(context){
                        return '/' + context.match[1] + context.match[2] + '.html'
                    }
                }
            ]
            ]
        },
        hot:true,//開(kāi)啟模塊熱更新
        hotOnly:true,
        proxy: {
            '/api': {
                target: 'https://blog.poetries.top',//代理到服務(wù)器
                changeOrigin:true,
                logLevel: 'debug',
                // pathRewite: { },
                headers:{}// 請(qǐng)求頭
            }
        }
    },
    plugin:[
        // 模塊熱更新插件
        new webpack.HotModuleReplacementPlugin()
        
        // 輸出熱更新路徑
        new webpack.NamedModulesPlugin()
    ]
}

模塊熱更新配置

需要通過(guò)module.hot

f (module.hot) {
  module.hot.accept('./library.js', function() {
    // Do something with the updated library module...
  })
}

5.2.4 開(kāi)啟調(diào)試SourceMap

Source Map調(diào)試

把生成以后代碼和之前的做一個(gè)映射

開(kāi)啟Source Map方式

JS Source Map設(shè)置

develpoment

  • eval
  • eval-source-map
  • cheap-eval-source-map
  • cheap-module-eval-source-map

推薦使用cheap-module-source-map

production

  • source-map
  • hidden-source-map
  • nosource-source-map

推薦使用source-map

CSS Source Map設(shè)置

改變loaderoptions選項(xiàng)

  • css-loader.options.soucemap
  • less-loader.options.soucemap
  • sass-loader.options.soucemap
module.exports = {
    entry: {
        app: './src/app.js'
    },
    
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: '/',
        filename: '[name].[hash:5].js'
    },
    module: {
        // 處理css的每個(gè)loader加上sourceMap: true 觀察css樣式 可以看到對(duì)應(yīng)的行號(hào)
        rules: [
            test: /\.less/,
            use: [
                {
                    loader: 'style-loader',
                    options: {
                        // singleton: true,會(huì)導(dǎo)致css的sourceMap不生效
                        //singleton: true,
                        sourceMap: true
                    }
                },
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 2,
                        sourceMap: true
                    }
                },
                {
                    loader: 'less-loader',
                    options: {
                        sourceMap: true
                    }
                }
            ]
        ]
    },
    devtool: 'cheap-module-eval-source-map',//開(kāi)啟sourcemap
    devServer: {
        port: 9001,
        // 輸入任意路徑都不會(huì)出現(xiàn)404 都會(huì)重定向
       // historyApiFallback: true
        historyApiFallback: {
            //從一個(gè)確定的url指向?qū)?yīng)的文件
            //rewrites: [
            //    {
            //        from: '/pages/a',// 可以寫(xiě)正則
           //         to: '/pages/a.html'
            //    }
            rewrites: [
                {
                    from: /^\/([a-zA-Z0-9]+\/?)([a-zA-Z0-9]+)/
                    to: function(context){
                        return '/' + context.match[1] + context.match[2] + '.html'
                    }
                }
            ]
            ]
        },
        hot:true,//開(kāi)啟模塊熱更新
        hotOnly:true,
        overlay:true,//錯(cuò)誤提示
        proxy: {
            '/api': {
                target: 'https://blog.poetries.top',//代理到服務(wù)器
                changeOrigin:true,
                logLevel: 'debug',
                // pathRewite: { },
                headers:{}// 請(qǐng)求頭
            }
        }
    },
    plugin:[
        // 模塊熱更新插件
        new webpack.HotModuleReplacementPlugin()
        
        // 輸出熱更新路徑
        new webpack.NamedModulesPlugin()
    ]
}

5.2.5 設(shè)置 ESLint 檢查代碼格式

  • eslint
  • eslint-loader
  • esling-plugin-html
  • eslint-frindly-formatter 友好提示錯(cuò)誤

配置eslint

  • wepback config 新增loader
  • .eslintrc或者在package.jsoneslintConfig中寫(xiě)

配置eslint的規(guī)范预鬓,推薦使用JavaScript standard style(https://standardjs.com)

需要安裝以下插件

  • eslint-config-standard
  • eslint-plugin-promise
  • eslint-plugin-standard
  • eslint-plugin-import
  • eslint-plugin-node

eslint-loader

  • options.failOnWarning 出現(xiàn)警告
  • options.failOnError
  • options.formatter
  • options.outputReport

設(shè)置 devServer.overlay在瀏覽器中看提示的錯(cuò)誤

// .eslintrc

module.exports = {
    root: true,
    extends: 'standard',
    plugins: [],
    env: {
        browsers: true,
        node: true // node環(huán)境
    },
    rules: {
        // 縮進(jìn)
        indent: ['error', 4],
        
        //換行
        "eol-last": ['error', 'never']
    }
}
module.exports = {
    entry: {
        app: './src/app.js'
    },
    
    output: {
        path: path.resolve(__dirname, 'dist'),
        publicPath: '/',
        filename: '[name].[hash:5].js'
    },
    module: {
        // 處理css的每個(gè)loader加上sourceMap: true 觀察css樣式 可以看到對(duì)應(yīng)的行號(hào)
        rules: [
            {
                test: /\.js$/,
                include: [path.resolve(__dirname,'src/')],
                exclude: [path.resolve(__dirname,'src/libs')],
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['env']
                        }
                    },
                    //eslint-loader需要在babel-loader之后處理
                    {
                        loader: 'eslint-loader',
                        options: {
                            formatter: require('eslint-frindly-formatter')
                        }
                    }
                ]
            },
            {
                test: /\.less/,
                use: [
                    {
                        loader: 'style-loader',
                        options: {
                            // singleton: true,會(huì)導(dǎo)致css的sourceMap不生效
                            //singleton: true,
                            sourceMap: true
                        }
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            importLoaders: 2,
                            sourceMap: true
                        }
                    },
                    {
                        loader: 'less-loader',
                        options: {
                            sourceMap: true
                        }
                    }
                ]
            }
        ]
    },
    devtool: 'cheap-module-eval-source-map',//開(kāi)啟sourcemap
    devServer: {
        port: 9001,
        // 輸入任意路徑都不會(huì)出現(xiàn)404 都會(huì)重定向
       // historyApiFallback: true
        historyApiFallback: {
            //從一個(gè)確定的url指向?qū)?yīng)的文件
            //rewrites: [
            //    {
            //        from: '/pages/a',// 可以寫(xiě)正則
           //         to: '/pages/a.html'
            //    }
            rewrites: [
                {
                    from: /^\/([a-zA-Z0-9]+\/?)([a-zA-Z0-9]+)/
                    to: function(context){
                        return '/' + context.match[1] + context.match[2] + '.html'
                    }
                }
            ]
            ]
        },
        hot:true,//開(kāi)啟模塊熱更新
        hotOnly:true,
        overlay:true,//錯(cuò)誤提示
        proxy: {
            '/api': {
                target: 'http://blog.poetries.top',//代理到服務(wù)器
                changeOrigin:true,
                logLevel: 'debug',
                // pathRewite: { },
                headers:{}// 請(qǐng)求頭
            }
        }
    },
    plugin:[
        // 模塊熱更新插件
        new webpack.HotModuleReplacementPlugin()
        
        // 輸出熱更新路徑
        new webpack.NamedModulesPlugin()
    ]
}

5.2.6 區(qū)分開(kāi)發(fā)環(huán)境 和 生產(chǎn)環(huán)境

開(kāi)發(fā)環(huán)境

  • 模塊熱更新
  • sourceMap
  • 接口代理
  • 代碼規(guī)范檢查

生產(chǎn)環(huán)境

  • 提取公共代碼
  • 壓縮
  • 文件壓縮或base64編碼
  • 去除無(wú)用的代碼

共同點(diǎn)

  • 入口一致
  • loader處理
  • 解析配置一致

使用webpack-merge合并公共配置

  • webpack.dev.conf.js
  • wepback.prod.conf.js
  • webpack.common.conf.js
"scripts":{
    "server": "wepback-dev-server --env development --open --config build/webpack.common.config.js",
    "build": "wepback --env production --open --config build/webpack.common.config.js"
}

公共配置 build/webpack.common.conf.js

const merge = require('webpack-merge')
const webpack = require('webpack')
const path = require('path')

const chalk = require('chalk')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ProgressBarPlugin = require('progress-bar-webpack-plugin')

const developmentConfig = require('./webpack.dev.conf')
const productionConfig = require('./webpack.prod.conf')


// 根據(jù)環(huán)境變量生成配置
const generateConfig = env =>{
    const extractLess = new ExtractTextWebpackPlugin({
        filename: 'css/[name]-bundle-[hash:5].css'
    })
    const scriptLoader = [
      'babel-loader'
    ].concat(env === 'production'
      ? []
      : [{
          loader: 'eslint-loader',
          options: {
              formatter: require('eslint-friendly-formatter')
          }
      }]
    )
    const cssLoaders = [
      {
          loader: 'css-loader',
          options: {
              importLoaders: 2,
              sourceMap: env==='development'
          }
      },
      {
        loader: "postcss-loader",
        options: {
          ident: "postcss",
          sourceMap: env==='development',
          plugins: [

          ].concat(env==='production'
            ? require('postcss-sprites')({
              spritePath: 'build/assets/imgs/sprites',
              retina: true
            })
            :[]
          )
        }
      },
      {
          loader: 'less-loader',
          options: {
              sourceMap: env==='development'
          }
      }
    ]
    const styleLoader = env === 'production'
          // 線上需要提取css成文件
          ? extractLess.extract({
            fallback:'style-loader',
            use: cssLoaders
          })
          : ['style-loader'].concat(cssLoaders)

    const fileLoader = env === 'development'
        ? [{
            loader: 'file-loader',
            options: {
              name: '[name]-[hash:5].[ext]',
              outputPath: 'assets/imgs/'
            }
          }]
        : [{
          loader: 'url-loader',
          options: {
            name: '[name]-[hash:5].[ext]',
            limit: 1000,//1k
            outputPath: 'assets/imgs/'
          }
        }]

    return {
      entry: {
          app: './src/index.js'
      },
      output: {
          path: path.resolve(__dirname, '../build'),
          publicPath: '/',
          filename: '[name]-bundle-[hash:5].js'
      },
      // 路徑解析
      resolve: {
          alias: {
              // jquery$: path.resolve(__dirname, '../src/libs/jquery.min.js')
          }
      },
      module: {
          rules: [
              {
                  test: /\.(js|jsx)$/,
                  include: [path.resolve(__dirname,'../src/')],
                  exclude : /node_modules/,
                  use: scriptLoader
              },
              {
                  test: /\.(less|css|scss)/,
                  use: styleLoader
              },
              {
                test: /\.(png|jpg|jpeg|gif)$/,
                use: fileLoader.concat(env==='production'
                  ? [
                    {
                      loader: 'img-loader',
                      options: {
                        pngquant: {
                          quality: 80
                        }
                      }
                    }
                  ]
                  : []
                )
              },
              {
                test: /\.(eot|woff2?|ttf|svg)$/,
                use: fileLoader
              }
          ]
      },
      plugins: [
        extractLess,

        new ProgressBarPlugin({
          format: '  build [:bar] ' + chalk.green.bold(':percent') + ' (:elapsed seconds)',
          clear: false
        }),
        new HtmlWebpackPlugin({
                inject: true,
                template: path.resolve(__dirname,'../public/index.html'),
          minify: {
            collapseWhitespace: true
          }
            }),
        new webpack.ProvidePlugin({
          $: 'jquery'
        })
      ]
    }
}


module.exports = env =>{
  const config = env==='development' ? developmentConfig : productionConfig
  return merge(generateConfig(env),config)
}

開(kāi)發(fā)環(huán)境配置 build/webpack.dev.conf.js

const webpack = require('webpack')
const path = require('path')

module.exports = {
    devtool: 'cheap-module-eval-source-map',//開(kāi)啟sourcemap
    devServer: {
        port: 9001,
        // 輸入任意路徑都不會(huì)出現(xiàn)404 都會(huì)重定向
        historyApiFallback: true,
        // historyApiFallback: {
            //從一個(gè)確定的url指向?qū)?yīng)的文件
            //rewrites: [
            //    {
            //        from: '/pages/a',// 可以寫(xiě)正則
           //         to: '/pages/a.html'
            //    }
            // rewrites: [
            //     {
            //         from: /^\/([a-zA-Z0-9]+\/?)([a-zA-Z0-9]+)/
            //         to: function(context){
            //             return '/' + context.match[1] + context.match[2] + '.html'
            //         }
            //     }
            // ]
        // },
        hot:true,//開(kāi)啟模塊熱更新
        hotOnly:true,
        overlay:true,//錯(cuò)誤提示
        proxy: {
            '/api': {
                // target: 'http://blog.poetries.top',//代理到服務(wù)器
                changeOrigin:true,
                logLevel: 'debug',
                // pathRewite: { },
                headers:{}// 請(qǐng)求頭
            }
        }
    },
    plugins: [
      // 模塊熱更新插件
       new webpack.HotModuleReplacementPlugin(),

       // 輸出熱更新路徑
       new webpack.NamedModulesPlugin()
    ]
}


生產(chǎn)環(huán)境配置 build/webpack.prod.conf.js

const webpack = require('webpack')
const PurifyCssWebpack = require('purifycss-webpack')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')

const path = require('path')
const glob = require('glob-all')//處理多個(gè)路徑

module.exports = {
  plugins: [
    new PurifyCssWebpack({
      paths: glob.sync([
        './*html',
        './src/*js'
      ])
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest'
    }),
    new HtmlWebpackPlugin({
      inlineChunks: ['manifest']
    }),
    new webpack.optimize.UglifyJsPlugin(),
    new CleanWebpackPlugin(['../build'])
  ]
}

5.3 使用 middleware 來(lái)搭建開(kāi)發(fā)環(huán)境

可以更靈活配置,需要以下插件搭建

  • Express or koa
  • webpack-dev-middleware
  • webpack-hot-middleware 熱更新
  • http-proxy-middleware 代理
  • connect-history-api-fallback 地址rewrite
  • opn 命令工具打開(kāi)瀏覽器頁(yè)面
// build/server.js

/**
 * 使用middleware搭建服務(wù):更靈活配置,不在使用webpack-dev-server
 * @type {[type]}
 */

const express = require('express')
const webpack = require('webpack')
const opn = require('opn')

const app = express()
const port = 3000

//把express和配置聯(lián)合起來(lái) 需要用到middleware
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpackHotMiddleware = require('webpack-hot-middleware')
const proxyMiddleware = require('http-proxy-middleware')
const historyApiFallback = require('connect-history-api-fallback')

const config = require('./webpack.common.conf')({env:'development'})
const compiler = webpack(config) //給express使用

const proxyTable = require('./proxy')

for(let context in proxyTable){
  app.use(proxyMiddleware(context, proxyTable[context]))
}

app.use(historyApiFallback(require('./historyfallback')))

app.use(webpackDevMiddleware(compiler, {
  publicPath: config.output.publicPath
}))

app.use(webpackHotMiddleware(compiler))


app.listen(port, function(){
  console.log('> Ready on:' + port)
  opn('http://localhost:' + port)
})

六、webpack實(shí)戰(zhàn)場(chǎng)景

詳情 http://blog.poetries.top/2018/11/21/webpack-review/#%E5%85%AD%E3%80%81webpack%E5%AE%9E%E6%88%98%E5%9C%BA%E6%99%AF

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赊颠,一起剝皮案震驚了整個(gè)濱河市格二,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌竣蹦,老刑警劉巖顶猜,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異痘括,居然都是意外死亡长窄,警方通過(guò)查閱死者的電腦和手機(jī)滔吠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)挠日,“玉大人疮绷,你說(shuō)我怎么就攤上這事∠保” “怎么了冬骚?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)懂算。 經(jīng)常有香客問(wèn)我只冻,道長(zhǎng),這世上最難降的妖魔是什么计技? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任喜德,我火速辦了婚禮,結(jié)果婚禮上酸役,老公的妹妹穿的比我還像新娘住诸。我一直安慰自己,他們只是感情好涣澡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布贱呐。 她就那樣靜靜地躺著,像睡著了一般入桂。 火紅的嫁衣襯著肌膚如雪奄薇。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,115評(píng)論 1 296
  • 那天抗愁,我揣著相機(jī)與錄音馁蒂,去河邊找鬼。 笑死蜘腌,一個(gè)胖子當(dāng)著我的面吹牛沫屡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播撮珠,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼沮脖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了芯急?” 一聲冷哼從身側(cè)響起勺届,我...
    開(kāi)封第一講書(shū)人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤想许,失蹤者是張志新(化名)和其女友劉穎忍级,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體棉圈,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡榕酒,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年胚膊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了故俐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡紊婉,死狀恐怖购披,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肩榕,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布惩妇,位于F島的核電站株汉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏歌殃。R本人自食惡果不足惜乔妈,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望氓皱。 院中可真熱鬧路召,春花似錦、人聲如沸波材。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)廷区。三九已至唯灵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間隙轻,已是汗流浹背埠帕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留玖绿,地道東北人敛瓷。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像斑匪,于是被迫代替她去往敵國(guó)和親呐籽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子秤标,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

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

  • 這幾天苍姜,那個(gè)陜西孕婦跳樓事件一度刷屏牢酵,驚著了眾多女同胞:孕婦、產(chǎn)婦衙猪、姑娘及姑娘媽馍乙。 昨天布近,看見(jiàn)侄女在朋友圈發(fā)一條這...
    橙藍(lán)子翔閱讀 475評(píng)論 0 2
  • 前些天看過(guò)一篇文章,其中提到了共享充電寶的種種不是丝格,包括適用場(chǎng)景撑瞧、衛(wèi)生狀況等等,是的显蝌,現(xiàn)在共享充電寶是有種種的問(wèn)題...
    觀富閱讀 321評(píng)論 1 1
  • 今日講的是一本比較陽(yáng)光的小說(shuō)由F·H·伯納特所寫(xiě)的《小公主》预伺,其電影由著名童星秀蘭·鄧波兒主演。 【故事梗概】: ...
    文穴LCAVE閱讀 1,179評(píng)論 0 6