webpack學習筆記(3)-webpack使用

webpack基本使用

// webpack4中除了正常安裝webpack以外,須要再單獨安一個webpack-cli

npm i webpack webpack-cli -D

基本命令行

webpack <entry> [<entry>] <output>css

配置文件使用

直接輸入webpack,默認執行: webpack.config.js or webpackfile.js文件;
若是想自定義文件名,運行:webpack --config webpack.conf.dev.jshtml

打包js

// ESmodule
export default function(a,b){
    return a+b
}
import sum from './sum'

// common.js規範

module.exports = function(a,b){
    return a-b
}
var minus = require('./minus')

// AMD規範,多了兩個bundle,異步加載
//amd規範
define(function(require, factory) {
    'use strict';
    return function(a,b){
        return a*b
    }
});

require(['./muti'],function(muti){
    console.log('muti,23,24='+muti(23,24))
})
console.log('sum,23,24='+sum(23,24))
console.log('minus,23,24='+minus(23,24))

編譯 ES 6/7

  • 安裝babel-loader, babel-core, babel-preset-env

npm install --save-dev babel-loader babel-core babel-preset-envnode

babel-loader:在import或加載模塊時,對es6代碼進行預處理,es6語法轉化爲es5語法。
babel-core:容許咱們去調用babel的api,能夠將js代碼分析成ast(抽象語法樹),方便各個插件分析語法進行相應的處理.
babel-preset-env:爲了告訴babel只編譯批准的內容,至關於babel-preset-es2015, es2016, es2017及最新版本。經過它可使用最新的js語法。jquery

  • 配置webpack.config.js
module.exports = {
    entry:{
        app:'./app.js'
    },
    output:{
        filename:'[name].[hash:5].js'
    },
    module:{
        rules:[
            {
                test:/\.js$/,
                use:{
                    loader:'babel-loader',
                    options:{
                        presets:[
                            // 最新的版本
                            ['@babel/preset-env',{ 
                                targets:{// 支持目標,數據來源於‘can i use’網站
                                    browsers:['> 1%','last 2 versions']
                                    //chrome:'52'
                                }
                            }]
                        ]
                    }
                },
                //排除相關文件
                exclude:'/node_modules/'
            }
        ]
    }
}

其中,exclude是定義不但願babel處理的文件。targets是presets的一些預設選項,這裏表示將js用於瀏覽器,只確保佔比大於1%的瀏覽器的特性,主流瀏覽器的最新兩個主版本。
更多與配置有關的信息,能夠參考:
babel env preset設置,
browserlist預設置webpack

因爲babel-preset配置選項較多,咱們通常能夠在根目錄下創建.babelrc文件,專門用來放置babel preset配置,這是一個json文件。能夠將上述配置修改以下:git

//.bablerc文件
{
    "presets": [
        ['env',{
            "targets": {
                "browsers": ['> 1%', 'last 2 versions']
            }
        }]
    ]
}

//原webpack.config.js文件
module: {
    rules: [
        {
            test: /\.js$/,
            use: {
                loader: 'babel-loader'
            },
            exclude: '/node_modules/'
        }
    ]
}

babel-polifill

在上面的babel配置中,babel只是將一些es6,es7-8的語法轉換成符合目標的js代碼,可是若是咱們使用一些特性或方法,好比Generator, Set, 或者一些方法。babel並不能轉換爲低版本瀏覽器識別的代碼。這時就須要babel-polifill。es6

簡單的說,polifill就是一個墊片,提供了一些低版本es標準對高級特性的實現。使用polifill的方法以下:github

npm install --save babel-polifill

而後在應用入口引入polifill,要確保它在任何其餘代碼/依賴聲明前被調用。web

//CommonJS module
require('babel-polyfill');

//es module
import 'babel-polifill';

在webpack.config.js中,將babel-polifill加入entry數組中:chrome

entry: ["babel-polifill", "./app.js"]

相比於runtime-transform,polifill用於應用開發中。會添加相應變量到全局,因此會污染全局變量。
更多配置參考:babel-polifill

完整代碼以下:

const path = require('path');
module.exports = {
    //entry爲入口,webpack從這裏開始編譯
    entry: [
        "babel-polyfill",
        path.join(__dirname, './src/index.js')
    ],
    //output爲輸出 path表明路徑 filename表明文件名稱
    output: {
        path: path.join(__dirname, './bundle'),
        filename: 'bundle.js'
    },
    //module是配置全部模塊要通過什麼處理
    //test:處理什麼類型的文件,use:用什麼,include:處理這裏的,exclude:不處理這裏的
    module: {
        rules: [
            {
                test: /\.js$/,
                use: ['babel-loader'],
                include: path.join(__dirname , 'src'),
                exclude: /node_modules/
            }
        ]
    },
};

runtime-transform插件

runtime transform也是一個插件,它與polifill有些相似,但它不污染全局變量,因此常常用於框架開發。
安裝:
*npm install --save-dev babel-plugin-transform-runtime

npm install --save babel-runtime*
用法:
將下面內容添加到.bablerc文件中

{
    "plugins": ["transform-runtime"]
}

更多配置參考:bable-runtime-transform插件

使用 loader 處理 CSS

1 . 安裝處理 css 相關 loader

// css-loader讓你能import css  , style-loader能將css以style的形式插入
$ npm install --save-dev css-loader style-loader
module.exports = {
    plugins: [require('autoprefixer')]  // 引用該插件便可了
}

而後在webpack裏配置postcss-loader

module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader', 'postcss-loader']
            }
        ]
    }
}

2 . 安裝 less 相關

npm install --save-dev less less-loader

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

npm i postcss-loader autoprefixer -D

建立 postcss.config.js 加入如下代碼

module.exports = {
    plugins: {
        'postcss-cssnext': {}
    }
}

4 . 實現

src/app.css

body {
  background: pink;
}

src/app.js

import css from './app.css';

console.log("hello world");
// 處理順序從右到左 less -> postcss -> css -> style
        {
           test: /\.css$/,
           use: [ 'style-loader', 'css-loader' ]
        }

5.用 mini-css-extract-plugin 把 CSS 分離成文件

npm install --save-dev mini-css-extract-plugin
rules: [
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            }
    ]


 new MiniCssExtractPlugin({
        filename: "[name].css",// 指定打包後的css
        chunkFilename: "[id].css"
 }),

6.壓縮與優化
打包 css 以後查看源碼,咱們發現它並無幫咱們作代碼壓縮,這時候須要使用 optimize-css-assets-webpack-plugin 這個插件,它不只能幫你壓縮 css 還能優化你的代碼。

npm install --save-dev optimize-css-assets-webpack-plugin
const optimizeCss = require('optimize-css-assets-webpack-plugin');
//配置
optimization: {
  minimizer: [new OptimizeCSSAssetsPlugin()];
}

clipboard.png

如上圖測試用例所示,因爲optimize-css-assets-webpack-plugin這個插件默認使用了 cssnano 來做 css 優化,
因此它不只壓縮了代碼、刪掉了代碼中無用的註釋、還去除了冗餘的 css、優化了 css 的書寫順序,優化了你的代碼 margin: 10px 20px 10px 20px; =>margin:10px 20px;。同時大大減少了你 css 的文件大小。更多優化的細節見文檔。

插件

生成HTML插件

安裝插件npm install --save-dev html-webpack-plugin 配置 webpack.config.js

npm install --save-dev html-webpack-plugin
const htmlWebpackPlugin = require('html-webpack-plugin');
...
plugins: [
    new htmlWebpackPlugin({
        filename: "index.html",  //打包後的文件名
        template: path.join(__dirname , "./src/index.html"),  // 用哪一個html做爲模板,在src目錄下建立一個index.html頁面當作模板來用
        hash: true, // 會在打包好的bundle.js後面加上hash串
    })
],

若是須要多頁面開發,能夠這樣寫:

let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    // 多頁面開發,怎麼配置多頁面
    entry: {
        index: './src/index.js',
        login: './src/login.js'
    },
    // 出口文件  
    output: {                       
        filename: '[name].js',
        path: path.resolve('dist')
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',   
            filename: 'index.html',
            chunks: ['index']   // 對應關係,index.js對應的是index.html
        }),
        new HtmlWebpackPlugin({
            template: './src/login.html',
            filename: 'login.html',
            chunks: ['login']   // 對應關係,login.js對應的是login.html
        })
    ]
}

html-webpack-plugin用法全解

清理打包文件插件

$ npm i clean-webpack-plugin --save-dev
const CleanWebpackPlugin = require('clean-webpack-plugin');
...
plugins: [
    ...
    new CleanWebpackPlugin(['bundle']) //傳入清楚路徑
]

提取公共代碼

緣由和優點

  • 緣由
    1.相同的資源被重複的加載,浪費用戶的流量和服務器的成本;
    2.每一個頁面須要加載的資源太大,致使網頁首屏加載緩慢,影響用戶體驗。
  • 優勢
    1.減小網絡傳輸流量,下降服務器成本;
    2.雖然用戶第一次打開網站的速度得不到優化,但以後訪問其它頁面的速度將大大提高。

optimization

在webpack4以前,提取公共代碼都是經過一個叫CommonsChunkPlugin的插件來辦到的。到了4之後,內置了一個如出一轍的功能,並且起了一個好聽的名字叫「優化」

下面咱們就來看看如何提取公共代碼

// 假設a.js和b.js都同時引入了jquery.js和一個寫好的utils.js
// a.js和b.js
import $ from 'jquery';
import {sum} from 'utils';

那麼他們兩個js中其中公共部分的代碼就是jquery和utils裏的代碼了

能夠針對第三方插件和寫好的公共文件

module.exports = {
    entry: {
        a: './src/a.js',
        b: './src/b.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve('dust')
    },
    // 提取公共代碼
+   optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {   // 抽離第三方插件
                    test: /node_modules/,   // 指定是node_modules下的第三方包
                    chunks: 'initial',
                    name: 'vendor',  // 打包後的文件名,任意命名    
                    // 設置優先級,防止和自定義的公共代碼提取時被覆蓋,不進行打包
                    priority: 10    
                },
                utils: { // 抽離本身寫的公共代碼,utils這個名字能夠隨意起
                    chunks: 'initial',
                    name: 'utils',  // 任意命名
                    minSize: 0    // 只要超出0字節就生成一個新包
                }
            }
        }
+   },
    plugins: [
        new HtmlWebpackPlugin({
            filename: 'a.html',
            template: './src/index.html',  // 以index.html爲模板
+           chunks: ['vendor', 'a']
        }),
        new HtmlWebpackPlugin({
            filename: 'b.html',
            template: './src/index.html',  // 以index.html爲模板
+           chunks: ['vendor', 'b']
        })
    ]
}

經過以上配置,能夠把引入到a.js和b.js中的這部分公共代碼提取出來,以下圖所示

clipboard.png

webpack-dev-server配置

安裝 webpack-dev-server

npm install --save-dev webpack-dev-server

webpack.config.js 添加配置

...
devServer: {
    contentBase: path.join(__dirname, 'bundle'),  //啓動路徑
    host:'localhost',  //域名,默認是localhost
    port: 8018,  //端口號
    open: true, //自動打開瀏覽器
    hot: true //開啓熱更新
}

固然在npm run dev命令下,打包的文件存在於內存中,並不會產生在dist目錄下

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

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

But這並沒那麼簡單,由於熱更新還須要配置一個webpack自帶的插件而且還要在主要js文件裏檢查是否有module.hot

下面就讓咱們直接看下代碼是如何實現的

// webpack.config.js
let webpack = require('webpack');

module.exports = {
    plugins: [
        // 熱更新,熱更新不是刷新
        new webpack.HotModuleReplacementPlugin()
    ],
    devServer: {
        contentBase: './dist',
        hot: true,
        port: 3000
    }
}

// 此時還沒完雖然配置了插件和開啓了熱更新,但實際上並不會生效

// index.js
let a = 'hello world';
document.body.innerHTML = a;
console.log('這是webpack打包的入口文件');

// 還須要在主要的js文件裏寫入下面這段代碼
if (module.hot) {
    // 實現熱更新
    module.hot.accept();
}

編譯圖片

  • file-loader
    對一些對象做爲文件來處理,而後能夠返回它的URL。
$ npm install --save-dev file-loader
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
  {
    loader: 'file-loader',
    options: { 
      name: '[name].[ext]', // 文件名和擴展名
      outputPath: 'images/'
    }
  },
  • url-loader
npm i file-loader url-loader -D
module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ExtractTextWebpackPlugin.extract({
                    use: 'css-loader',
                    publicPath: '../'
                })
            },
            {
                test: /\.(jpe?g|png|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 8192,    // 小於8k的圖片自動轉成base64格式,而且不會存在實體圖片
                            outputPath: 'images/'   // 圖片打包後存放的目錄
                        }
                    }
                ]
            }
        ]
    }
}
  • 解析 html 代碼裏面 img 的標籤

html-loader: html 變成導出成字符串的過程當中,還能進行壓縮處理(minimized)

$ npm install --save-dev html-loader
...
{
  test: /\.(gif|png|jpe?g|svg)$/i,
  use: [
    {
      loader: 'file-loader',
      options: {
        name: '[name].[ext]',
        outputPath: 'images/'
      }
    },
  ]
},
// 下面幾行纔是 html-loader 的配置內容
{
  test: /\.html$/,
  use: [ {
    loader: 'html-loader',
    options: {
      minimize: true
    }
  }],
}
...
  • 壓縮圖片

image-webpack-loader:壓縮圖片文件

$  npm install image-webpack-loader --save-dev
{
  test: /\.(gif|png|jpe?g|svg)$/i,
  use: [
    {
      loader: 'file-loader',
      options: {
        name: '[name].[ext]',
        outputPath: 'images/'
      }
    },
    {
      loader: 'image-webpack-loader',
      options: {
        bypassOnDebug: true,
      }
    }
  ]
},
{
  test: /\.html$/,
  use: [ {
    loader: 'html-loader',
    options: {
      minimize: true
    }
  }],
}

resolve解析

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

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

打包速度

webpack 4 在項目中實際測了下,廣泛能提升 20%~30%的打包速度。

首先你須要知道你目前打包慢,是慢在哪裏。

咱們能夠用 speed-measure-webpack-plugin 這個插件,它能監控 webpack 每一步操做的耗時。以下圖:

clipboard.png

能夠看出其實大部分打包花費的時間是在Uglifyjs壓縮代碼。和前面的提高熱更新的切入點差很少,查看source map的正確與否,exclude/include的正確使用等等。

相關文章
相關標籤/搜索