Webpack 4 使用指南

sdafsef發表於2018-04-15

最近想學一學Webpack,在網上看了很多相關文章,但是Webpack更新的太快了,很多文章都不適用weback新的版本,我從頭開始研究了一番,在這裡和大家分享交流一下,有錯誤的地方請指出.

簡介

  • 從頭開始搭建一個Webpack專案
  • 遇到的各種警告
  • 打包js檔案
  • 處理css檔案
  • 外掛使用
  • 提取公共js庫
  • webpack-dev-server 等...

一 . 搭建一個webpack專案

首先你需要一個node.js (我的版本 node v8.9.4, npm v5.6.0 )
建立一個資料夾 mkdir webpack-my 進入資料夾 cd webpack-my
建立專案 npm init 一路回車
安裝webpack webpack-cli(想要執行webpack的命令必須有這個包)
--save-dev 是隻新增依賴到開發環境
npm install --save-dev webpack webpack-cli
window下執行應該有幾條警告 警告雖然沒多大關係但我們還是來看一下
WARN nomnom@1.8.1: Package no longer supported... nomnom包過時了不用管它
WARN babel-preset-es2015@6.24.1 babel推薦讓使用 babel-preset-env 我們下面再安裝
WARN webpack-my@1.0.0 No repository field 沒有倉庫地址的警告可以在 npm init命令裡設定或修改package.json:

"repository": {
    "type": "git",
    "url": "http://path.xxx"
}
複製程式碼

或者設定 "private": true 設定為私有
webpack-my@1.0.0 No description 沒寫描述,基本同上...
兩個 WARN SKIPPING OPTIONAL DEPENDENCY: fsevents@1.1.3 fsevent是mac osx系統的,警告忽略之... (微強迫症,警告不看全不舒服...)

二 . 處理js檔案

1 . 安裝babel

處理js檔案我們需要用到bable,先安裝一下
npm install --save-dev babel-loader babel-core

2 . 安裝 babel-preset-env

它用來轉義es6等 babel-preset-env介紹
npm install --save-dev babel-preset-env
在根目錄下建立 .babelrc 檔案, 加入以下程式碼

{
    "presets": ["env"]
}
複製程式碼

3 . 解決瀏覽器相容及效能問題

為防止瀏覽器不支援 Promise/Object.assign/Array.from等還有效能問題,我們引入兩個包:

npm install --save-dev babel-polyfill babel-plugin-transform-runtime
引入生產版本依賴 npm install --save babel-runtime 通過 .babelrc 新增配置

{
    "presets": [
        "env"
    ],
    "plugins": [
       "transform-runtime"
    ]
}
複製程式碼

babel-polyfill 需要在 webpack中配置下面會說到

4 . 讓我們來配置一下webpack :

建立 src/bundle資料夾作為我們存放/生成程式碼的地方
建立 webpack.config.js 檔案作為webpack的配置檔案
path為node.js內建的,用來處理路徑的, __dirname是node.js的全域性屬性,代表當前路徑。
將 babel-polyfill 加到你的 entry 陣列中使用
配置js檔案要經過babel轉義

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/
            }
        ]
    },
};
複製程式碼

好了讓我們來試驗一下,在src裡建立 text-0.js text-1.js text-2.js index.js 內容分別為:

export const Text0 = "小明";
複製程式碼
export const Text1 = "在公司";
複製程式碼
export const Text2 = "寫程式碼";
複製程式碼
import {Text0} from './text-0.js';
import {Text1} from './text-1.js';
import {Text2} from './text-2.js';

const textFun = (...arg) => {
    let P = document.createElement("p");
    P.innerHTML = arg.join(" ");
    document.getElementById('root').appendChild(P);
}
textFun(Text0,Text1,Text2);
複製程式碼

5 . 使用webpack

控制檯輸入 npx webpack --config webpack.config.js npx是什麼
根據webpack.config.js打包檔案
等等出現了什麼 WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/ 原來是讓我們設定開發或者生產模式
webpack.config.js 裡設定

mode: 'development'
複製程式碼

為了方便使用我們在 package.json 里加入webpack打包的命令方便我們使用修改 script

"scripts": {
    "build": "npx webpack --config webpack.config.js"
 },
複製程式碼

這樣再次執行我們直接輸入 npm run build
js檔案打包好了,讓我們建立一個html頁面看看效果吧,在bundle資料夾下建立 index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    </head>
    <body>
        <div id='root'></div>
        <script type="text/javascript" src="./bundle.js" charset="utf-8"></script>
    </body>
</html>
複製程式碼

注意在這裡寫了一個script標籤引入 bundle.js
開啟html檔案看看效果吧

Webpack 4 使用指南

如果你想看看打包出來的js檔案,你可以在 webpack.config.js 裡新增 devtool 屬性 屬性配置
圖簡單的話直接配置 devtool: '' 就可以了.

三 . 處理less檔案

1 . 安裝處理 css 相關 loader

npm install --save-dev css-loader style-loader
css-loader讓你能import css  , style-loader能將css以style的形式插入

2 . 安裝 less 相關

npm install --save-dev less less-loader

3 . 安裝 postcsspostcss-cssnext 新增瀏覽器字首

npm install --save-dev postcss-loader postcss-cssnext
建立 postcss.config.js 加入以下程式碼

module.exports = {
    plugins: {
        'postcss-cssnext': {}
    }
}
複製程式碼

我在這裡嘗試 autoprefixer 外掛但是好像不管用,可能還依賴別的包.

4 . 配置webpack

webpack.config.js -> module -> rules 裡新增配置
處理順序從右到左 less -> postcss -> css -> style

{
    test: /\.less$/,
    use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader']
}
複製程式碼

四 . 外掛

1 . 生成HTML外掛

安裝外掛
npm install --save-dev html-webpack-plugin 配置 webpack.config.js

const htmlWebpackPlugin = require('html-webpack-plugin');
...
plugins: [
    new htmlWebpackPlugin({
        filename: "index.html",  //打包後的檔名
        template: path.join(__dirname , "./src/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, shrink-to-fit=no">
    </head>
    <body>
        <div id='root'></div>
    </body>
</html>
複製程式碼

html-webpack-plugin用法全解
刪除 bundle 資料夾下所有檔案
重新執行 npm run build 看看效果吧

2 . 生成CSS外掛

安裝外掛(目前必須有@next)
npm install --save-dev extract-text-webpack-plugin@next
新增配置 webpack.config.js

const ExtractTextPlugin = require('extract-text-webpack-plugin');
...
module: {
    rules: [
        ...
        {
            test: /\.less$/,
            use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: ['css-loader', 'postcss-loader', 'less-loader']
            })
        }
    ]
},
plugins: [
    ...
    new ExtractTextPlugin({
        filename: 'index.css'
    }),
],
複製程式碼

3 . 清理打包檔案外掛

上述程式碼所打出的包名稱一直是一樣的,很容易造成快取問題
我們在 webpack.config.js 中做一下修改
outoup 下的 filename: 'bundle.js'filename: 'bundle.[hash:8].js'
plugins -> ExtractTextPlugin 下的 filename: 'index.css'filename: 'index.[hash:8].css'
快取的問題解決了,但是我們每次生成的都是不同名字的檔案 bundle 資料夾裡的東西越來越多,我們需要一個外掛來清理它.
安裝外掛 npm install --save-dev clean-webpack-plugin
修改 webpack.config.js

const CleanWebpackPlugin = require('clean-webpack-plugin');
...
plugins: [
    ...
    new CleanWebpackPlugin(['bundle'])
]
複製程式碼
====== 2018.09.26 update ======

4 . 程式碼壓縮件外掛

npm install uglifyjs-webpack-plugin -D 安裝程式碼壓縮外掛
修改 webpack.config.js

const uglify = require('uglifyjs-webpack-plugin');
...
plugins: [
    ...
    new uglify()
]
複製程式碼

五 . 提取公共js

webpack.config.js 裡新增

output: {
    ...
    chunkFilename: '[name].[chunkhash:8].js'
},
...
optimization: {
    splitChunks: {
        cacheGroups: {
            vendor: {
                test: /[\\/]node_modules[\\/]/,
                name: 'common',
                chunks: 'all'
            }
        }
    }
},
複製程式碼

參考文章 webpack4 splitChunksPlugin && runtimeChunkPlugin 配置雜記

六 . webpack-dev-server配置

安裝 webpack-dev-server
npm install --save-dev webpack-dev-server webpack.config.js 新增配置

...
devServer: {
    contentBase: path.join(__dirname, 'bundle'),  //啟動路徑
    host:'localhost',  //域名
    port: 8018,  //埠號
}
複製程式碼

執行命令 npx webpack-dev-server --config webpack.config.js
為了方便使用新增 package.json 中,加入 --color(顏色) --progress(進度) --hot(熱載入)

"scripts": {
    "build": "npx webpack --config webpack.config.js",
    "start": "npx webpack-dev-server --config webpack.config.js --color --progress --hot"
 },
複製程式碼

七 . 編譯圖片

npm install --save-dev url-loader file-loader
webpack.config.js -> rules增加配置:

{
   test: /\.(png|jpg|gif)$/,
   use: [{
       loader: 'url-loader',
       options: {
           limit: 8192  //8k一下的轉義為base64
       }
   }]
}
複製程式碼

總結

到這裡一個擁有基礎功能的webpack包就建好了,後續有什麼想到的東西我會繼續更新...
以後可能會加上React , 專案的程式碼放在我的github
第一次寫文章,有什麼問題請告訴我~

====== 2018.5.13 update ======

筆者回來慢慢填坑了

八 . CSS Modules 使用

使用 CSS Modules 來模組化我們的CSS 修改我們的 webpack.config.js -> module -> rules

{
    test: /\.less$/,
    use: ExtractTextPlugin.extract({
        fallback: "style-loader",
-       use: ['css-loader', 'postcss-loader', 'less-loader'],
+       use: ['css-loader?modules&localIdentName=[local]-[hash:base64:5]', 'postcss-loader', 'less-loader']
    })
}
複製程式碼

這樣我們所有經過 rulesless 名字都被加了hash了
在我們的 index.less 中加入

.module-test{
    background-color: green;
    color: blue;
}
複製程式碼

對應我們在 index.js 中加入

//替換之前的引入
import style from './index.less';

const textFun = (...arg) => {
    let P = document.createElement("p");
    P.innerHTML = arg.join(" ");
+   P.className = style["module-test"];
    document.getElementById('root').appendChild(P);
}
複製程式碼

執行 npm run build
好了我們遇到一個問題,之前寫的 #root 也被 CSS Modules 改變了 可是我們的 #root 是寫在 index.html 裡的
我們把 #root 改成這樣 :global(#root) 這樣就不會被改變了.

====== 2018.5.20 update ======

後續暫時沒什麼時間繼續更新文章了(想開新坑...)。
我做了一些關於多頁面打包、公共庫提取、公共程式碼提取的配置
在我的 github
歡迎來訪,同時求個star 求個Fork

====== 2018.07.15 update ======

熱載入設定
webpack.config.js 中的 devServer 加入 hot: true
entry 入口新增 webpack/hot/only-dev-server 開啟熱載入
需要熱載入的頁面加入

if (module.hot) {
    module.hot.accept();
}
複製程式碼

開啟熱載入

注意這種配置在多頁面情況下只有首頁可以熱模組載入 其他的頁面不行

====== 2018.07.16 update ======

加上 source-map 能看清楚錯誤在哪個檔案
devtool: 'source-map'

參考文章

Webpack4 那點兒東西
從零搭建React全家桶框架教程
webpack中文網
babel中文網

相關文章