webpack 4.X之學習

創(chuàng)建配置文件webpack.config.js

在根目錄在手動創(chuàng)建webpack.config.js,配置基本模板

module.exports ={
    entry:{},
    output:{},
    module:{},
    plugins:[],
    devServer:{}
}

  • entry:配置入口文件的地址,可以是單一入口,也可以是多入口;
  • output:配置出口文件的地址,支持多出口配置;
  • module:配置模塊,主要解析CSS和圖片轉換壓縮等功能;
  • plugins:配置插件;
  • devServer:配置開發(fā)服務功能;

entry選項配置

這個選項配置我們要壓縮的文件一般是javascript。

entry:{
    entry:'./src/entery.js'
}

output選擇配置

出口配置用來告訴webpack最后打包文件的地址和文件名稱;

output:{
    //打包后的文件路徑
    path: path.resolve(__dirname,'dist'),
    //打包后的文件名稱
    filename:'bundle.js'
}

當然還要引入path模塊,這個是nodejs自帶的模塊;在webpack.config.js文件的頭部引入;

const path = require('path');

現(xiàn)在的代碼結構:

const path = require('path');
module.exports={
    //入口文件的配置項
    entry:{
        entry:'./src/entry.js'
    },
    //出口文件的配置項
    output:{
        //輸出的路徑,用了Node語法
        path:path.resolve(__dirname,'dist'),
        //輸出的文件名稱
        filename:'bundle.js'
    },
    //模塊:例如解讀CSS,圖片如何轉換,壓縮
    module:{},
    //插件,用于生產(chǎn)模版和各項功能
    plugins:[],
    //配置webpack開發(fā)服務功能
    devServer:{}
}

多入口,出口配置

const path = require('path');
module.exports={
    //入口文件的配置項
    entry:{
        entry:'./src/entry.js',
        //這里我們又引入了一個入口文件
        entry2:'./src/entry2.js'
    },
    //出口文件的配置項
    output:{
        //輸出的路徑,用了Node語法
        path:path.resolve(__dirname,'dist'),
        //輸出的文件名稱
        filename:'[name].js'
    },
    //模塊:例如解讀CSS,圖片如何轉換,壓縮
    module:{},
    //插件,用于生產(chǎn)模版和各項功能
    plugins:[],
    //配置webpack開發(fā)服務功能
    devServer:{}
}

服務和熱更新配置

首先,配置devServer

devServer:{
    contentBase:path.resolve(__dirname,'dist'),
    host:'localhost',
    compress:true,
    port:1608
}

  • contentBase:服務器基本運行路徑
  • host:服務器運行地址
  • compress:服務器壓縮式,一般為true
  • port:服務運行端口

然后,下載webpack-dev-server模塊,

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

最后,配置package.json里的scripts選項

 "scripts": {
    "server": "webpack-dev-server"
}

運行命令 npm run server ,服務器運行,在瀏覽器中打開http://localhost:1608,既可以看到頁面;

當 npm run server 啟動后,服務器有一種監(jiān)控機制(watch),可以實現(xiàn)熱更新;

js壓縮

webpack自帶一個插件uglifyjs-webpack-plugin來壓縮js,所以不需要再次安裝,當一切都準備妥當,引入uglifyjs-webpack-plugin模塊:

const uglify = require('uglifyjs-webpack-plugin');

因為它是一個插件,所以把它放在plugins里:

plugins:[
    new uglify()
]

這樣就完事了,執(zhí)行命令webpack,壓縮文件就OK了,一般不會出現(xiàn)問題,(但是我在實際操作中報錯了,uglifyjs-webpack-plugin沒有找到,所以,如果你報錯了,還是安裝一下吧)

npm install uglifyjs-webpack-plugin --save-dev

打包HTML文件

首先刪除dist目錄下的所有文件,然后在src文件下創(chuàng)建index.html文件,

/src/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>webpack</title>
</head>
<body>
    <div id="title"></div>
</body>
</html>

配置webpack.config.js文件,安裝html-webpack-plugin插件

npm install html-webpack-plugin --save-dev

然后引入改插件:

const htmlPlugin =  require('html-webpack-plugin');

在plugins下,加載htmlPlugin插件

plugins:[
    new uglify(),
    new htmlPlugin({
        minify:{
            removeAttributeQuotes:true
        },
        hash:true,
        template:'./src/index.html'
    })
]

  • minify:是對html文件進行壓縮, removeAttributeQuotes是去掉屬性的雙引號;
  • hash:為了開發(fā)中js有緩存效果,加入hash,可以有效避免js緩存;
  • template:需要打包的HTML模板路徑和文件名稱;

Loaders

Loaders是Webpack最重要的功能之一,他也是Webpack如此盛行的原因。通過使用不同的Loader,Webpack可以的腳本和工具,從而對不同的文件格式進行特定處理。

Loader的配置模型:

  • test:用于匹配處理文件的擴展名的表達式,這個選項是必須進行配置的;
  • use:loader名稱,就是你要使用模塊的名稱,這個選項也必須進行配置,否則報錯;
  • include/exclude:手動添加必須處理的文件(文件夾)或屏蔽不需要處理的文件(文件夾)(可選);
  • query:為loaders提供額外的設置選項(可選)。

打包CSS

首先,在src目錄下建立css文件夾,和index.css文件,并編寫如下代碼:

body{
    background: burlywood;
    color:white;
    font-size:30px;
}

建立好后,需要引入到入口文件中,才可以打包。在entery.js的首行加入代碼:

import css from './css/index.css';

接下來我們就需要解析css文件,通過loader,下面到我們下載style-loader和css-loader:

npm install style-loader css-loader --save-dev

配置loader:

第一種方法:(推薦第一種)

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

第二種方法:

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

第三種方法:

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

這樣我們就配置好了,使用命令webpack打包,就可以看的樣式生效;

分離CSS

目前,打包后的文件中,css是打包在js代碼里面的,這樣不便于以后的維護,所以需要吧CSS從js中分離出來,我們需要使用插件Extract Text Plugin

安裝:

npm install --save-dev extract-text-webpack-plugin

在webpack.config.js中引入

const ExtractTextPlugin = require('extract-text-webpack-plugin');

在Plugins中配置:

new ExtractTextPlugin('css/index.css');
//css/index.css是分離后的路徑位置

修改Loader配置:

module:{
    rules:[
        {
            test:/\.css$/,
            use:ExtractTextPlugin.extract({
                fallback:"style-loader",
                use:"css-loader"
            })
        }
    ]
}

Less打包和分離

Less作為目前很火的CSS預處理語言,它擴展了 CSS 語言,增加了變量、Mixin、函數(shù)等特性,使 CSS 更易維護和擴展;

安裝:

npm install --save-dev less less-loader

在webpack.config.js中配置Loader:

module:{
    rules:[
        {
            test:/\.less$/,
            use:ExtractTextPlugin.extract({
                fallback:"style-loader",
                use:[{
                    loader:"css-loader"
                },{
                    loader:"less-loader"
                }]
            })
        }
    ]
}

Sass打包和分離

Sass的打包和分離和less的類似,首先下載安裝Sass所支持的服務與loader

安裝:

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

在webpack.config.js中配置Loader:

module:{
    rules:[
        {
            test:/\.less$/,
            use:ExtractTextPlugin.extract({
                fallback:"style-loader",
                use:[{
                    loader:"css-loader"
                },{
                    loader:"sass-loader"
                }]
            })
        }
    ]
}

css自動加載前綴

CSS3是目前作為一個前端必須要掌握的技能,但是由于現(xiàn)在好多瀏覽器還是不兼容CSS3,所以前端需要多寫很丑很難看的前綴代碼;以前都是邊查Can I Use ,邊添加,這樣很麻煩,現(xiàn)在配置一個插件postcss就可以搞定;

PostCSS是一個CSS的處理平臺,它可以幫助你的CSS實現(xiàn)更多的功能,但是今天我們就通過其中的一個加前綴的功能,初步了解一下PostCSS。

安裝:

npm install --save-dev postcss-loader autoprefixer

第一種方式
在根目錄下,建立一個postcss.config.js文件:

module.exports = {
    plugins:[
        require('autoprefixer')
    ]
}

這就是對postCSS一個簡單的配置,引入了autoprefixer插件。讓postCSS擁有添加前綴的能力,它會根據(jù) can i use 來增加相應的css3屬性前綴。

在webpack.config.js中配置Loader:

{
    test: /\.css$/,
    use: extractTextPlugin.extract({
        fallback: 'style-loader',
        use: [
            { loader: 'css-loader', 
                options: { importLoaders: 1 } 
            },
            'postcss-loader'
        ]
    })

}

第二種方式
postcss直接在webpack.config.js中配置Loader:


{
                test:/\.css$/,
                
                use: ExtractTextPlugin.extract({
                  fallback: 'style-loader',
                  use: [
                      {
                          loader: 'css-loader',
                          options: {
                              importLoaders: 1
                          }
                      },
                      {
                          loader: 'postcss-loader',
                          options: {
                              ident: 'postcss',
                              plugins: (loader) => [
                                  require('autoprefixer')()
                                  // require('cssnano')()
                              ]
                          }
                      }
                  ]
              })
}

消除多余CSS

隨著項目的進展,編寫的CSS會越來越多,有時候需求更改,帶來DOM結構的更改,造成CSS的冗余,所以為了減少CSS文件的體積,需要消除冗余的CSS;使用PurifyCSS可以大大減少CSS冗余;這個插件必須配合extract-text-webpack-plugin來使用;

安裝:

npm install --save-dev purifycss-webpack purify-css

引入glob:

因為需要同步檢查HTML模板,所以需要引入node的glob對象使用,在webpack.config.js文件頭部引入

const glob = require('glob');

引入purifycss-webpack:

const PurifyCssPlugin = require('purifycss-webpack');

配置plugins:

plugins:[
    new PurifyCssPlugin({
        paths:glob.sync(path.join(__dirname,'src/*.html'))
    })
]

CSS中圖片處理

在src目錄下新建一個images目錄,把圖片放入images文件夾中;在index.html文件中增加一個div標簽:

/src/index.html:

<div id="image"></div>

編寫css,給剛剛增加的div標簽添加背景圖片:

/src/css/index.css:

#image{
    background: url('../images/webpack.jpg');
    width: 497px;
    height: 270px;
}

安裝loader:

npm install --save-dev file-loader url-loader

在webpack.config.js中配置loader:

module:{
    rules:[
        {
            test:/\.(png|jpg|gif)$/,
            use:[{
                loader:'url-loader',
                options:{
                    limit:500000,
                    outputPath:'images/'
                }
            }]
        }
    ]
}

url-loader與file-loader

file-loader:解決引用路徑的問題;

url-loader:如果圖片較多,會發(fā)很多http請求,降低頁面性能,url-loader將引入的圖片編碼,生成dataURL;url-loader會提供一個limit參數(shù)(單位B),小于limit字節(jié)的圖片會被轉為dataURL,大于limit的會使用file-loader進行copy;outputPath是圖片分離后的路徑;

簡單說兩者關系,url-loader封裝了file-loader,url-loader不依賴file-loader,即使用url-loader時,只需要安裝url-loader即可,不需要安裝file-loader;

CSS中圖片路徑處理

利用extract-text-webpack-plugin插件將CSS文件分離出來,但是CSS里的圖片路徑并不正確,這里使用publicPath解決;

publicPath是在webpack.config.js文件的output選項中,主要作用是處理靜態(tài)文件路徑的;

聲明一個website對象:

const website = {
    publicPath:'http://localhost:1608/'
}

這里的IP和端口,必須和devServer配置的IP和端口一致。

配置output選擇:

output:{
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js',
    publicPath: website.publicPath
}

HTML中圖片處理

在webpack中是不喜歡你使用標簽<img>來引入圖片的,但是作前端特別熱衷于這種寫法,國人也為此開發(fā)了一個:html-withimg-loader。他可以很好的處理我們在html 中引入圖片的問題。

安裝loader:

npm install --save-dev html-withimg-loader

在webpack.config.js中配置loader:

module:{
    rules:[
        {
            test:/\.(htm|html)$/,
            use:["html-withimg-loader"]
        }
    ]
}

Babel是什么

Babel是一個編譯JavaScript的平臺,它的強大之處表現(xiàn)在可以通過編譯幫你達到:

  • 使用下一代的javascript(ES6,ES7,……)代碼,即使當前瀏覽器沒有完成支持;
  • 使用基于JavvScript進行擴展語言,比如React的JSX;

webpack配置Babel

安裝依賴包:

npm install --save-dev babel-core babel-loader babel-preset-react babel-preset-env

  • babel-core:babel的核心包;
  • babel-loader:babel的loader包;
  • babel-preset-es2015:解析es6的包;
  • babel-preset-env:解析es6的包;(官方最新推薦)
  • babel-preset-react:解析React的JSX的包;

在webpack.config.js中配置babel:

module:{
    rules:[
        {
            test:'/\.(js|jsx)$/',
            use:{
                loader:'babel-loader'
            },
            exclude:/node_module/
        }
    ]
}

在根目錄下建立.babelrc文件,雖然Babel可以直接在webpack.config.js中進行配置,但是考慮到babel具有非常多的配置選項,如果卸載webapck.config.js中會非常的雍長不可閱讀,所以我們經(jīng)常把配置卸載.babelrc文件里。

.babelrc

{
    "presets":["env","react"]
}

打包第三方類庫

在工作中引入第三方的類庫是在所難免的,比如引入JQuery;那么如何引入呢?下面我們來說說:

首先我們安裝第三方類庫,這里用jquery為例子:

npm install jquery --save

要注意的是這里我們使用“--save”來安裝模塊,因為引入的第三方類庫肯定是需要在生產(chǎn)環(huán)境要用;

第二步,就是要引入第三方類庫了,這里有兩種方法來引入:

第一種,在/src/entery.js(即入口文件)中,直接引入jquery:

/src/entery.js

import $ from 'jquery';

一行簡單的import命令就ok了;

第二種,就是在webpack配置文件中,全局引入jquery:

/webpack.config.js

plugins:[
    new webpack.ProvidePlugin({
        $:'jquery'
    })
]

通過webpack自帶的插件ProvidePlugin;

兩種方法的區(qū)別:

  • import引入方法:引用后不管你在代碼中使用不適用該類庫,都會把該類庫打包起來,這樣有時就會讓代碼產(chǎn)生冗余。
  • ProvidePlugin引入方法:引用后只有在類庫使用時,才按需進行打包,所以建議在工作使用插件的方式進行引入。

抽離第三方類庫

上面說到如何引入和打包第三方類庫,通過上面的方法有一個問題,那就是將第三方類庫全部打包到/src/entery.js中,增加了文件的大小,和復雜度;因此,我們需要抽離第三方類庫:

首先,修改入口文件:

/webpack.config.js

entry:{
    entry:'./src/entery.js',
    jquery:'jquery'
}

接著,使用optimize優(yōu)化插件

plugins:[
    new webpack.optimize.CommonsChunkPlugin({
        name:['jqury'],
        filename:'assets/js/[name].js',
        minChunks:2
    })
]

  • name :對應入口文件的名字;
  • filename : 文件抽離后的路徑;
  • minChunks : 固定配置,必寫;

靜態(tài)資源打包

在工作中可能會有一些在項目中沒有引用的圖片資源或者是其他靜態(tài)資源,但是又必須留著,這時我們就需要處理這些靜態(tài)資源;

下載安裝插件copy-webpack-plugin

npm install --save-dev copy-webpack-plugin

配置webpack.config.js文件:

const CopyPlugin = require('copy-webpack-plugin');
    ...
plugins:[
    new CopyPlugin([{
        from:__dirname + '/src/public',
        to:'./public'
    }])
]

  • from:要打包的靜態(tài)資源源目錄地址
  • to:要打包到的文件夾路徑

watch的配置

/webpack.config.js

watchOptions:{
    poll:1000,
    aggregateTimeout:500,
    ignored:/node_module/
}

  • poll:檢測修改的時間,單位毫秒
  • aggregateTimeout:防止重復保存的時間,單位毫秒
  • ignored:忽略的目錄

如何打包多頁面

在學了webpack之后,我的感受是我會配置webpack了,也能運行了,但是學習的過程中都是單頁面的,那么多頁是如何打包的呢?其實多頁面的打包和單頁面的打包的原理是一樣的,只是多配置幾個對應的入口,和出口,以及HtmlWebpackPlugin對象;當然你完全可以像下面這樣:

const config = {
    entry:{
        index:'./src/index.js',
        info:'./src/index.js'
    },
    output:{
        path: path.join(__dirname, 'dist'),
        filename: 'js/[name].js'
    }
    ...
    plugins:[
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: './src/index.html',
            chunks:['index'],
            hash: true,
            minify: {
                removeAttributeQuotes:true,
                removeComments: true,
                collapseWhitespace: true,
                removeScriptTypeAttributes:true,
                removeStyleLinkTypeAttributes:true
            }
        }),
        new HtmlWebpackPlugin({
            filename: 'info.html',
            template: './src/info.html',
            hash: true,
            chunks:['info'],
            minify: {
                removeAttributeQuotes:true,
                removeComments: true,
                collapseWhitespace: true,
                removeScriptTypeAttributes:true,
                removeStyleLinkTypeAttributes:true
            }
        })
    ]
}

細心的你肯定發(fā)現(xiàn)我改變了幾個地方,一是,把output.filename的‘js/index.js’變成了‘js/[name].js’,這是因為我們是多頁面,每個頁面對應相應的js這樣方便管理,二是,在HtmlWebpackPlugin對象中添加了chunks這個屬性,chunk屬性是讓你選擇對應的js模塊;

上面這種寫法當然是沒有問題,這是只有兩個頁面無所謂,那么有十個甚至更多呢,我們一直做著重復的事,這不是我們程序員的風格,我們就是為了能夠偷懶才做程序員的不是嗎?(當然還有高工資(#.#)),接下來我們來抽離這些重復的事;

首先,我們通過Node的glob對象,來獲取我們存在的html或js;

/**
*
* @param {string}  globPath  文件的路徑
* @returns entries
*/
function getView(globPath,flag){
    let files = glob.sync(globPath);

    let entries = {},
    entry, dirname, basename, pathname, extname;

    files.forEach(item => {
        entry = item;
        dirname = path.dirname(entry);//當前目錄
        extname = path.extname(entry);//后綴
        basename = path.basename(entry, extname);//文件名
        pathname = path.join(dirname, basename);//文件路徑
        if (extname === '.html') {
            entries[pathname] = './' + entry;
        } else if (extname === '.js') {
            entries[basename] = entry;
        }
    });

    return entries;
}

既然,我們已經(jīng)有了getView()函數(shù),可以獲取html和js文件,那么我們就可以確定有多少個入口,和多少個頁面;

let entriesObj = getView('./src/js/*.js');

let config = {
    entry:entriesObj,
    ...
}

上面我們就配置好了入口,不需要我們手動添加了,有多少js就有多少入口;

let pages = Object.keys(getView('./src/*html'));

pages.forEach(pathname => {
    let htmlname = pathname.split('src\\')[1];
    let conf = {
        filename: `${htmlname}.html`,
        template: `${pathname}.html`,
        hash: true,
        chunks:[htmlname],
        minify: {
            removeAttributeQuotes:true,
            removeComments: true,
            collapseWhitespace: true,
            removeScriptTypeAttributes:true,
            removeStyleLinkTypeAttributes:true
        }
    }

    config.plugins.push(new HtmlWebpackPlugin(conf));
});

最后,我們獲取HTML頁面,和添加對應頁面的HTMLWebpackPlugin對象;

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容