webpack4初學習

webpack基於node,所以想要學習webpack首先要安裝node。
webpack4要安裝node8.2以上版本。css

一、安裝webpack

爲何選擇本地安裝,主要是因爲之後介紹熱更新這一部分不會報錯,若是全局安裝熱更新就會報錯,以本部分爲基礎依次介紹,保證各部分不會出錯。html

mkdir webpack-test
cd webpack-test
npm init //初始化npm,都選擇默認,文件夾自動建立package.json
npm i webpack webpack-cli -D  // 本地安裝webpack

★ npm i -D 是 npm install --save-dev 的簡寫,是指安裝模塊並保存到 package.json 的 devDependencies中,主要在開發環境中的依賴包node

二、初試0配置打包

webpack4能夠支持0配置打包,這裏所說的0配置又是什麼呢?固然在開發者眼中0配置的東西,那根本是沒法用的,由於不夠智能,那麼咱們就來看看作到了哪些0配置。
在使用webpack進行打包的時候,默認狀況下會將src下的入口文件(index.js)進行打包。jquery

a. 根目錄下建立文件夾src,並建立index.js文件webpack

document.write('Hello webpack!')

b. 打包測試css3

  • 若是直接打包:

clipboard.png
最後提示:
WARNING in configuration //配置警告
大致意思:是mode沒有設置,webpack生產環境沒法獲取mode值,請設置mode來肯定開發環境仍是生產環境web

  • 經過如下手段皆能夠不報錯:
// node v8.2版本之後都會有一個npx
// npx會執行bin裏的文件

npx webpack     // 不設置mode的狀況下 打包出來的文件自動壓縮
npx webpack --mode development  // 設置mode爲開發模式,打包後的文件不被壓縮

clipboard.png

當執行npx webpack命令的時候,webpack會自動查找項目中src目錄下的index.js文件,而後進行打包,生成一個dist目錄並存在一個打包好的main.js文件
這些算是0配置的操做了,名字都是定義好的,不能變,想一想也很雞肋npm

目錄結構:
clipboard.pngjson

三、配置執行文件

  • 從新建立目錄:lesson_test
  • 初始化:npm init //所有選擇默認便可
  • 建立webpack.config.js配置文件

webpack.config.js基本配置項:api

module.exports = {
    entry: '',               // 入口文件
    output: {},              // 出口文件
    module: {},              // 處理對應模塊
    plugins: [],             // 對應的插件
    devServer: {},           // 開發服務器配置
    mode: 'development'      // 模式配置
}

a.根目錄下建立src文件夾,並在src目錄下建立index.js:

document.write('Hello webpack!')

b.配置文件webpack.config.js:

const path = require('path')

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './dist')
    },
    mode: 'development'
}

c.執行webpack

clipboard.png

經過簡單打包,在根目錄下多出一個文件夾

clipboard.png

clipboard.png

查看一下dist文件夾下bundle.js可見如下代碼,證實打包成功
clipboard.png


友情提示:

在咱們每次npm run build的時候都會在dist目錄下建立不少打好的包,若是積累過多可能也會混亂,因此應該在每次打包以前將dist目錄下的文件都清空,而後再把打好包的文件放進去
這裏提供一個clean-webpack-plugin插件

npm i clean-webpack-plugin -D

webpack.config.js中添加如下配置代碼:

let CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
    plugins: [
        // 打包前先清空
        new CleanWebpackPlugin('dist')  
    ]
}

四、配置開發環境/生產環境

上邊部分咱們測試已經發現,直接打包會警告配置環境,本部分着重介紹一下。

環境配置在package.json文件:

{
  "name": "lesson_test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack --mode development", // 開發環境,和上部分npx webpack --mode development對比咱們能夠發現點端倪
    "build": "webpack --mode production" // 生產環境
  },
  "author": "",
  "license": "ISC"
}

開發環境和生產環境打包會有什麼區別呢?
"dev": "webpack --mode development", // 開發環境,打包後文件是未壓縮的文件
"build": "webpack --mode production" // 生產環境,打包後文件是壓縮過的文件

配置完成後,經過執行命令:

a. 執行 npm run dev

clipboard.png

打包後文件爲非壓縮文件

clipboard.png

b. 執行 npm run build

clipboard.png

打包後文件爲壓縮文件

clipboard.png

五、多文件入口配置

假如src目錄下多個文件入口,又該如何配置webpack.config.js文件呢。
clipboard.png

具體方案:

  • 一種是沒有關係的可是要打包到一塊兒去的,能夠寫一個數組,實現多個文件打包
  • 另外一種就是每個文件都單獨打包成一個文件的

下面就來看看這兩種方式的寫法,配置代碼:

const path = require('path')

module.exports = {
    // 1.寫成數組的方式就能夠打出多入口文件,不過這裏打包後的文件都合成了一個
    // entry: ['./src/index.js', './src/login.js'],
    // 2.真正實現多入口和多出口須要寫成對象的方式
    entry: {
        index: './src/index.js',
        login: './src/login.js'
    },
    output: {
        // 1. filename: 'bundle.js',
        // 2. [name]就能夠將出口文件名和入口文件名一一對應
        //filename: '[name].js', // 打包後會生成index.js和login.js文件
        filename: '[name].[hash:16].js', //生成文件名含有16位哈希值
        path: path.resolve(__dirname, 'dist')
    },
    mode: 'development'
}

執行npm run dev結果

clipboard.png

目錄結構(生成文件的名字帶有16位哈希值):

clipboard.png

六、打包html配置

webpack的核心功能是打包js的,html、style、css、less、sass、img等等須要引入各類loader,到達這一部分,每一步都須要引入對應的插件。

html須要安裝html-webpack-plugin插件,開始引入:

npm i html-webpack-plugin -D  // 本地安裝

由於是個插件,因此須要在webpack.config.js裏引用一下。

a. 單文件入口配置

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin') // 引入html打包插件

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'index.js',
        path: path.resolve(__dirname, 'dist')
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            hash: true // 在html模板中自動添加?20位哈希值
        })
    ],
    mode: 'development'
}

執行npm run dev 生成目錄

clipboard.png

打開index.html文件,可見js文件後添加了「?20位哈希值」
clipboard.png

b. 多文件入口配置

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry: {
        main: './src/index.js',
        login: './src/login.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            chunks: ['main'],  // 對應關係,main.js對應的是index.html,這裏特地修改成main,方便理解,如下會和目錄文件做對比就一目瞭然了
            hash: true // 在html模板中自動添加?20位哈希值
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login'],  // 對應關係,index.js對應的是index.html
            hash: true // 在html模板中自動添加?20位哈希值
        })
    ],
    mode: 'development'
}

由目錄可見,dist文件夾下生成index.html對應main.js、login.html對應login.js
clipboard.png

clipboard.png

clipboard.png

上面基本介紹完了html和js的打包配置了,如今咱們還缺一個好兄弟css,webpack對css的解析須要用到loader,因此咱們先提早安裝好,待會好方便使用

七、引入css文件

這裏涉及到兩種樣式:

  • html頁面內style樣式 <style>/具體樣式/</style>,本部分介紹
  • html引入外部樣式表 <link href="..." rel="stylesheet" />第8部分介紹
npm i style-loader css-loader -D  // style\css

// 引入less文件的話,也須要安裝對應的loader
npm i less less-loader -D

文件目錄結構
clipboard.png

a. 配置樣式
clipboard.png

clipboard.png

b. 在js文件中引入樣式

clipboard.png

clipboard.png

c. 配置webpack.config.js文件

說明:配置module添加規則,本部分添加可css、less的匹配打包規則

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    entry: {
        main: './src/index.js',
        login: './src/login.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.less$/,
                use: ['style-loader', 'css-loader', 'less-loader']
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            chunks: ['main'],  // 對應關係,index.js對應的是index.html
            hash: true // 在html模板中自動添加?20位哈希值
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login'],  // 對應關係,index.js對應的是index.html
            hash: true // 在html模板中自動添加?20位哈希值
        })
    ],
    mode: 'development'
}

d. 執行npm run dev打包

生成靜態文件index.html

clipboard.png

生成靜態文件login.html

clipboard.png

  • 此時打包後的css文件是以行內樣式style的標籤寫進打包後的html頁面中,若是樣式不少的話,咱們更但願直接用link的方式引入進去,這時候須要把css拆分出來
  • extract-text-webpack-plugin插件相信用過的人都知道它是幹什麼的,它的功效就在於會將打包到js裏的css文件進行一個拆分

八、拆分css文件

本部分也就是將css文件拆分出來,html頁面以<link>的方式引入。

// @next表示能夠支持webpack4版本的插件
npm i extract-text-webpack-plugin@next -D

配置webpack.config.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin') // 引入插件

module.exports = {
    entry: {
        main: './src/index.js',
        login: './src/login.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    // 將css用link的方式引入就再也不須要style-loader了
                    use: 'css-loader'
                })
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            chunks: ['main'],
            hash: true
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login'],
            hash: true
        }),
        new ExtractTextWebpackPlugin('css/style.css') // 拆分後會把css文件放到dist目錄下的css/style.css
    ],
    mode: 'development'
}

配置中只對index.html文件引入樣式,而login.html沒有引入,所以要註釋掉login.js引入的樣式

// import './less/style.less' // 註釋掉這句代碼

document.write('<h1 class="color-blue">Welcome to webpack!</h1>')

執行npm run dev,生成dist目錄

clipboard.png

首頁靜態頁面代碼,可見以link的方式引入了css樣式

clipboard.png

九、拆分多個css文件

配置webpack.config.js文件

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')

// 樣式處理
const styleCss = new ExtractTextWebpackPlugin('./css/style.css')
const styleLess = new ExtractTextWebpackPlugin('./css/style2.css')

module.exports = {
    entry: {
        main: './src/index.js',
        login: './src/login.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: styleCss.extract({
                    use: 'css-loader'
                })
            },
            {
                test: /\.less$/,
                use: styleLess.extract({
                    use: ['css-loader', 'less-loader'], // 必定要注意這裏
                    fallback: 'style-loader' // 缺乏這裏也是沒法編譯less
                })
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            chunks: ['main'],  // 對應關係,index.js對應的是index.html
            hash: true // 在html模板中自動添加?20位哈希值
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login'],  // 對應關係,index.js對應的是index.html
            hash: true // 在html模板中自動添加?20位哈希值
        }),
        styleCss,
        styleLess
    ],
    mode: 'development'
}

index.js文件

import './css/style.css'
import './less/style.less' // 引入style.less

document.write('<h1 class="color-red">Hello webpack!</h1><h2 class="color-blue">測試less樣式是否引入</h2>')

執行 npm run dev ,獲取靜態頁面截圖,可見所有正常引入

clipboard.png

執行效果

clipboard.png

生成文件目錄:

clipboard.png

十、樣式表引用圖片

  • 處理圖片方面,也須要loader
npm i file-loader url-loader -D

這裏着重介紹一下file-loader和url-loader:

  • 本部分介紹url-loader(加強的file-loader);
  • url-loader做用:根據需求選擇性的把某些小圖片編碼成base64格式寫進頁面;從而減小服務器請求。優化性能。

url-loader解決的問題:
若是圖片較多,會發不少http請求,會下降頁面性能。url-loader會將引入的圖片編碼,生成dataURl。至關於把圖片數據翻譯成一串字符。再把這串字符打包到文件中,最終只須要引入這個文件就能訪問圖片了。固然,若是圖片較大,編碼會消耗性能。所以url-loader提供了一個limit參數,小於limit字節的文件會被轉爲DataURl,大於limit的還會使用file-loader進行copy。

url-loader和file-loader是什麼關係呢?
簡答地說,url-loader封裝了file-loader。url-loader不依賴於file-loader,即便用url-loader時,只須要安裝url-loader便可,不須要安裝file-loader,由於url-loader內置了file-loader。

經過上面的介紹,咱們能夠看到,url-loader工做分兩種狀況:
1.文件大小小於limit參數,url-loader將會把文件轉爲DataURL;
2.文件大小大於limit,url-loader會調用file-loader進行處理,參數也會直接傳給file-loader。所以咱們只須要安裝url-loader便可。


若是是在css文件裏引入的如背景圖之類的圖片,就須要指定一下相對路徑
webpack.config.js配置:

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')

// 樣式處理
const styleCss = new ExtractTextWebpackPlugin('./css/style.css')
const styleLess = new ExtractTextWebpackPlugin('./css/style2.css')

module.exports = {
    entry: {
        main: './src/index.js',
        login: './src/login.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: styleCss.extract({
                    use: 'css-loader',
                    publicPath: '../' // 樣式根據相對路徑引用到圖片資源
                })
            },
            {
                test: /\.less$/,
                use: styleLess.extract({
                    use: ['css-loader', 'less-loader'],
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192, // 小於8k的圖片自動轉成base64格式,而且不會存在實體圖片
                            outputPath: 'images' // 圖片輸出路徑
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            chunks: ['main'],
            hash: true
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login'],
            hash: true
        }),
        styleCss,
        styleLess
    ],
    mode: 'development'
}

樣式style.css代碼:

/* style.css */
@charset "utf-8";

.logo {
    display: block;
    width: 222px;
    height: 222px;
    background: url(../images/logo.png) no-repeat; // 這裏的logo.png大小大於8K,如下生成在dist文件夾下images目錄
}
.color-red {
    color: #f00;
}

在css中指定了publicPath路徑這樣就能夠根據相對路徑引用到圖片資源了,以下圖所示

clipboard.png

執行npm run dev 生成目錄結構:

clipboard.png

十一、js文件引入圖片

url-loader能自動識別CSS代碼中的圖片路徑並將其打包至指定目錄,可是JS就不一樣了,咱們來看下面的例子。

// index.js
var img = new Image();
img.src = './images/logo.png';
document.body.appendChild(img);

若是不使用Webpack打包,正常狀況下只要路徑正確圖片是可以正常顯示的。然而,當使用Webpack打包後,咱們會發現圖片並未被成功打包到dist目錄,天然圖片也沒法顯示出來。
這實際上是由於Webpack並不知道'../images/logo.png'是一張圖片,若是要正常打包的話須要先將圖片資源加載進來,而後再將其做爲圖片路徑添加至圖片對象。具體代碼以下:

// index.js
import imgUrl from './images/logo.png' // 引入圖片(路徑),若是小於8K格式爲base64,大於8K爲設置路徑dist目錄下'./images/logo.png'

const img = new Image() // 實例一個圖片對象
img.src = imgUrl;
document.body.appendChild(img); // 添加到dom節點中

完整index.js文件:

import './css/style.css'
import './less/style.less'
import imgUrl from './images/logo.png' // 引入圖片

const img = new Image()
img.src = imgUrl
document.body.appendChild(img)
// document.write(imgUrl) // './images/logo.png'

document.write('<h1 class="logo"></h1></h1><h1 class="color-red">Hello webpack!</h1><h2 class="color-blue">測試第二個css樣式是否引入</h2>')

完整webpack.config.js配置文件(相比第10部分無任何變化):

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')

// 樣式處理
const styleCss = new ExtractTextWebpackPlugin('./css/style.css')
const styleLess = new ExtractTextWebpackPlugin('./css/style2.css')

module.exports = {
    entry: {
        main: './src/index.js',
        login: './src/login.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: styleCss.extract({
                    use: 'css-loader',
                    publicPath: '../' // 樣式根據相對路徑引用到圖片資源
                })
            },
            {
                test: /\.less$/,
                use: styleLess.extract({
                    use: ['css-loader', 'less-loader'],
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,
                            outputPath: 'images', // 圖片輸出路徑
                            name: '[name].[ext]'
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            chunks: ['main'], // 對應關係,index.js對應的是index.html
            hash: true // 在html模板中自動添加?20位哈希值
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login'], // 對應關係,index.js對應的是index.html
            hash: true // 在html模板中自動添加?20位哈希值
        }),
        styleCss,
        styleLess
    ],
    mode: 'development'
}

執行npm run dev生成文件目錄

clipboard.png

生成靜態文件

clipboard.png
可見圖片在js中正常加載到頁面中,因爲logo.png大於8K,被打包到dist文件目錄的images文件中。若是圖片小於8K,則以base64編碼格式寫入頁面進項渲染。

clipboard.png

十二、html頁面引入圖片

頁面中常常會用到img標籤,img引用的圖片地址也須要一個loader來進行處理

npm i html-withimg-loader -D

完整wabpack.config.js配置:

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')

// 樣式處理
const styleCss = new ExtractTextWebpackPlugin('./css/style.css')
const styleLess = new ExtractTextWebpackPlugin('./css/style2.css')

module.exports = {
    entry: {
        main: './src/index.js',
        login: './src/login.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: styleCss.extract({
                    use: 'css-loader',
                    publicPath: '../' // 樣式根據相對路徑引用到圖片資源
                })
            },
            {
                test: /\.less$/,
                use: styleLess.extract({
                    use: ['css-loader', 'less-loader'],
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,
                            outputPath: 'images', // 圖片輸出路徑
                            name: '[name].[ext]'
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader' // 引入html-withimg-loader
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            chunks: ['main'], // 對應關係,index.js對應的是index.html
            hash: true // 在html模板中自動添加?20位哈希值
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login'], // 對應關係,index.js對應的是index.html
            hash: true // 在html模板中自動添加?20位哈希值
        }),
        styleCss,
        styleLess
    ],
    mode: 'development'
}

打包後生成對應目錄:

clipboard.png

1三、引入字體圖片和SVG圖片

字體圖標和svg圖片均可以經過file-loader來解析,在第11部分已經進行安裝。
webpack.config.js引入loader

module.exports = {
    module: {
        rules: [
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            outputPath: 'iconfont' // 打包到指定文件夾
                        }
                    }
                ]
            }
        ]
    }
}

這樣即便樣式中引入了這類格式的圖標或者圖片都沒有問題了,img若是也引用svg格式的話,配合上面寫好的html-withimg-loader就都沒有問題了。

在index.js引入樣式:

import './css/style.css'
import './less/style.less'
import './iconfont/iconfont.css' // 引入字體圖片
import imgUrl from './images/pic.jpg' // 引入圖片連接

const img = new Image()
img.src = imgUrl
document.body.appendChild(img)
// document.write(imgUrl) // './images/logo.png'

document.write('<h1 class="logo"></h1></h1><h1 class="color-red">Hello webpack!</h1><h2 class="color-blue">測試第二個css樣式是否引入</h2><br><span class="iconfont icon-gouwuche"></span>')

完整的webpack.config.js配置:

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')

// 樣式處理
const styleCss = new ExtractTextWebpackPlugin('./css/style.css')
const styleLess = new ExtractTextWebpackPlugin('./css/style2.css')

module.exports = {
    entry: {
        main: './src/index.js',
        login: './src/login.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: styleCss.extract({
                    use: 'css-loader',
                    publicPath: '../' // 樣式根據相對路徑引用到圖片資源
                })
            },
            {
                test: /\.less$/,
                use: styleLess.extract({
                    use: ['css-loader', 'less-loader'],
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,
                            outputPath: 'images', // 圖片輸出路徑
                            name: '[name].[ext]'
                        }
                    }
                ]
            },
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            outputPath: 'iconfont' // 打包到指定文件夾
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader' // 引入html-withimg-loader,將圖片轉化爲base64圖片
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            chunks: ['main'],
            hash: true
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login'],
            hash: true
        }),
        styleCss,
        styleLess
    ],
    mode: 'development'
}

打包後目錄文件:

clipboard.png

對應靜態文件

clipboard.png

1四、添加CSS3前綴

經過postcss中的autoprefixer能夠實現將CSS3中的一些須要兼容寫法的屬性添加響應的前綴,這樣省去咱們很多的時間

npm i postcss-loader autoprefixer -D // 安裝postcss-loader 和 autoprefixer

安裝後,咱們還須要像webpack同樣寫一個config的配置文件,在項目根目錄下建立一個postcss.config.js文件,配置以下:

const Autoprefixer = require('autoprefixer')

module.exports = {
    plugins : [
        Autoprefixer
    ]
}

clipboard.png

而後在webpack裏配置postcss-loader,webapack.config.js完整代碼:

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')

// 樣式處理
const styleCss = new ExtractTextWebpackPlugin('./css/style.css')
const styleLess = new ExtractTextWebpackPlugin('./css/style2.css')

module.exports = {
    entry: {
        main: './src/index.js',
        login: './src/login.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: styleCss.extract({
                    use: ['css-loader', 'postcss-loader'], // 配置postcss-loader
                    fallback: 'style-loader',
                    publicPath: '../'
                })
            },
            {
                test: /\.less$/,
                use: styleLess.extract({
                    use: ['css-loader', 'less-loader'],
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,
                            outputPath: 'images',
                            name: '[name].[ext]'
                        }
                    }
                ]
            },
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            outputPath: 'iconfont'
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader'
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            chunks: ['main'],
            hash: true
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login'],
            hash: true
        }),
        styleCss,
        styleLess
    ],
    mode: 'development'
}

index.js添加測試元素

clipboard.png

樣式表style.css,簡單書寫了animation動畫效果,沒有添加兼容瀏覽器的前綴

/* style.css */
@charset "utf-8";

.logo {
    display: block;
    width: 222px;
    height: 222px;
    background: url(../images/logo.png) no-repeat;
}
.color-red {
    color: #f00;
}
.test-css3 {
    position: absolute;
    left: 500px;
    top: 0;
    width: 100px;
    height: 100px;
    background-color: #f00;
    animation: myfirst 5s linear 2s infinite alternate running;
}
@keyframes myfirst {
    0% {
        background: #f00;
        left: 500px;
        top: 0;
    }
    25% {
        background: #ff0;
        left: 900px;
        top: 0;
    }
    50% {
        background: #f0f;
        left: 900px;
        top: 400px;
    }
    75% {
        background: #000;
        left: 500px;
        top: 400px;
    }
    100% {
        background: #0f0;
        left: 500px;
        top: 0;
    }
}

執行npm run dev 後生成的style.css代碼自動添加了-webkit-前綴

clipboard.png

1五、轉義ES6

在實際開發中,咱們在大量的使用着ES6及以後的api去寫代碼,這樣會提升咱們寫代碼的速度,不過因爲低版本瀏覽器的存在,不得不須要轉換成兼容的代碼,因而就有了經常使用的Babel。
bable能夠將ES6代碼轉義ES5代碼,安裝以下:

npm i babel-core babel-loader babel-preset-env babel-preset-stage-0 -D

babel兼容ES6和草案api,經過一個.babelrc文件來配置一下,對這些版本的支持

// .babelrc
{
    "presets": ["env", "stage-0"]   // 從右向左解析
}

咱們再在webpack裏配置一下babel-loader既能夠作到代碼轉成ES5了

module.exports = {
    module: {
        rules: [
            {
                test:/\.js$/,
                use: 'babel-loader',
                include: /src/,          // 只轉化src目錄下的js
                exclude: /node_modules/  // 排除掉node_modules,優化打包速度
            }
        ]
    }
}

添加本部分配置,完整wabpack.config.js代碼:

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

// 樣式處理
const styleCss = new ExtractTextWebpackPlugin('./css/style.css')
const styleLess = new ExtractTextWebpackPlugin('./css/style2.css')

module.exports = {
    entry: {
        main: './src/index.js',
        login: './src/login.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: styleCss.extract({
                    use: ['css-loader', 'postcss-loader'],
                    fallback: 'style-loader',
                    publicPath: '../' // 樣式根據相對路徑引用到圖片資源
                })
            },
            {
                test: /\.less$/,
                use: styleLess.extract({
                    use: ['css-loader', 'less-loader'],
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.js$/,
                use: 'babel-loader',
                include: '/src/',
                exclude: '/node_modules/'
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,
                            outputPath: 'images', // 圖片輸出路徑
                            name: '[name].[ext]'
                        }
                    }
                ]
            },
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            outputPath: 'iconfont' // 打包到指定文件夾
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader' // 引入html-withimg-loader,將圖片轉化爲base64圖片
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            chunks: ['main'], // 對應關係,index.js對應的是index.html
            hash: true // 在html模板中自動添加?20位哈希值
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login'], // 對應關係,index.js對應的是index.html
            hash: true // 在html模板中自動添加?20位哈希值
        }),
        styleCss,
        styleLess,
        new CleanWebpackPlugin('dist')
    ],
    mode: 'development'
}

1六、啓動靜態服務器和熱更新

A.啓動靜態服務

啓動一個靜態服務器,默認會自動刷新,就是說你對html,css,js文件作了修改並保存後,瀏覽器會默認刷新一次展示修改後的效果

module.exports = {
    devServer: {
        contentBase: './dist',
        host: 'localhost',      // 默認是localhost
        port: 8080,             // 端口
        open: true,             // 自動打開瀏覽器
        // hot: true               // 開啓熱更新
    }
}

此時咱們要對pakage.json文件進行修改:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --mode production", 
    "dev": "webpack-dev-server --mode development --open" // 使用webpack-dev-server
  }

執行npm run dev 會自動打開默認瀏覽器,打開http://localhost:8080頁面,html,css,js修改保存後頁面會自動實時更新。
以前各部分咱們每次執行npm run dev都會在根目錄生成靜態文件目錄dist,啓動靜態服務器,生成dist會儲存到內存當中,根目錄下再也不生成dist文件夾。

B.熱更新
在配置devServer的時候,若是hot爲true,就表明開啓了熱更新

module.exports = {
    devServer: {
        contentBase: './dist',
        host: 'localhost',      // 默認是localhost
        port: 8080,             // 端口
        open: true,             // 自動打開瀏覽器
        hot: true               // 開啓熱更新
    }
}

可是熱更新是指定某個js文件的更新,只需在指定的js文件添加如下代碼,表示本文件實現熱更新,修改文件後手動刷新頁面,會看到修改後的內容;若是不添加如下代碼,js文件仍是自動刷新

if (module.hot) {
    // 實現熱更新
    module.hot.accept();
}

熱更新和自動刷新的區別:

  • js文件被檢測到module.hot,就實現熱更新,檢測不到就是自動刷新;
  • 熱更新須要手動刷新獲取修改後效果,自動刷新是修改保存,頁面自動更新。

完整webpack.config.js代碼:

const path = require('path')
const webpack = require('webpack')  // 引入webpack
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')

// 樣式處理
const styleCss = new ExtractTextWebpackPlugin('./css/style.css')
const styleLess = new ExtractTextWebpackPlugin('./css/style2.css')

module.exports = {
    entry: {
        main: './src/index.js',
        login: './src/login.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: styleCss.extract({
                    use: ['css-loader', 'postcss-loader'],
                    fallback: 'style-loader',
                    publicPath: '../'
                })
            },
            {
                test: /\.less$/,
                use: styleLess.extract({
                    use: ['css-loader', 'less-loader'],
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.js$/,
                use: 'babel-loader',
                include: '/src/',
                exclude: '/node_modules/'
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,
                            outputPath: 'images',
                            name: '[name].[ext]'
                        }
                    }
                ]
            },
            {
                test: /\.(eot|ttf|woff|svg)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            outputPath: 'iconfont'
                        }
                    }
                ]
            },
            {
                test: /\.(htm|html)$/,
                use: 'html-withimg-loader'
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: 'index.html',
            title: '首頁測試',
            chunks: ['main'],
            hash: true
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            title: '登陸頁測試',
            chunks: ['login'],
            hash: true
        }),
        styleCss,
        styleLess,
        new CleanWebpackPlugin('dist'),
        new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
        contentBase: path.join(__dirname, 'dist'),
        host: 'localhost',
        port: 8080,
        open: true,
        hot: true // 實現頁面熱更新
    },
    resolve: {
        extensions: ['.js', '.json', '.css']
    },
    mode: 'development'
}

index.js文件代碼:

import './css/style.css'
import './less/style.less'
import './iconfont/iconfont.css'
import imgUrl from './images/pic.jpg' // 引入圖片

const img = new Image()
img.src = imgUrl
document.body.appendChild(img)
// document.write(imgUrl) // './images/logo.png'

document.write('<h1 class="logo"></h1></h1><h1 class="color-red">Hello webpack!</h1><h2 class="color-blue">測試第二個css樣式是否引入</h2><br><span class="iconfont icon-gouwuche"></span><span class="iconfont icon-new"></span><div class="test-css3"></div>')

if (module.hot) {
    module.hot.accept()
}

1七、resolve解析

在webpack的配置中,resolve咱們經常使用來配置別名和省略後綴名

module.exports = {
    resolve: {
        // 別名
        alias: {
            $: './src/jquery.js'
        },
        // 省略後綴
        extensions: ['.js', '.json', '.css']
    },
}

未完待續

參考連接:
一、https://juejin.im/post/5adea0...
二、https://www.cnblogs.com/cisum...
三、https://www.cnblogs.com/golov...
四、https://www.webpackjs.com/loa...
五、https://www.cnblogs.com/golov...

相關文章
相關標籤/搜索