webpack5搭建vue3教程

vue-cli 5.0的webpack版本是5,本教程一些慣例盡量和vue-cli保持一致,求同存異.
你需要了解一些基本的webpack知識(shí),比如loader,plugins,resolve

1. 初始化

新建一個(gè)目錄,在該目錄下執(zhí)行命令

npm init

會(huì)提示你一些選項(xiàng),除了入口文件默認(rèn)是index.js,我們這里和vue-cli保持一直輸入main.js,剩下的直接回車就好.
會(huì)在目錄下生成一個(gè)package.json文件

image.png

image.png

2.搭建webpack環(huán)境

npm i webpack webpack-merge webpack-dev-serve webpack-cli -D

webpack是必裝的,這個(gè)就不用介紹了
webpack-merge 這個(gè)是用來(lái)合并webpack配置文件的,比如一般項(xiàng)目有三個(gè)webpack配置文件,一個(gè)基礎(chǔ)的 打包圖片 樣式啥的,一個(gè)生產(chǎn)環(huán)境的,一個(gè)開發(fā)環(huán)境的.開發(fā)環(huán)境就需要把基礎(chǔ)配置文件合并進(jìn)來(lái)再export
webpack-dev-serve 提供一個(gè)本地serve服務(wù)器,webpack5自帶了一個(gè)serve但是傳言日志不好,暫時(shí)還是dev serve

3.創(chuàng)建目錄和文件

image.png

創(chuàng)建紅框里的目錄和文件,其中index.html為了一致性直接用的vue-cli的index.html.把對(duì)ico文件的link那一行刪掉

<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

當(dāng)然,你也可以自己定義一個(gè)更簡(jiǎn)單的,比如這樣

<!DOCTYPE html>
<html lang="">
  <body>
    <div id="app"></div>
  </body>
</html>

4.基本配置

我們先做一個(gè)最簡(jiǎn)單的配置,看看webpack能不能跑起來(lái)

webpack.common.js配置

const path = require('path')

module.exports = env =>{
    return {
        entry:'./src/main.js',//入口文件
        stats: 'errors-only',//僅錯(cuò)誤時(shí)顯示logo
        output:{
            filename: 'assets/js/[name].code.js',
            chunkFilename: 'assets/js/[name].bundle.js',//動(dòng)態(tài)導(dǎo)入 分離bundle 比如lodashjs配合注釋import(/* webpackChunkName: "lodash" */ 'lodash') 會(huì)打包成lodash.bundle.js
            path: path.resolve(__dirname, '../dist'),
        }
    }
}

webpack.prod.js配置

//const webpack = require('webpack');
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = env =>{
    let pro_config = {
        mode:'production',
        // devtool:'source-map',//開啟將會(huì)生成map文件
    }

    return merge(common(env),pro_config)  //合并配置
}

main.js

console.log('this is mainjs')

package.json

  "scripts": {
    "build": "webpack  --config build/webpack.prod.js"
  },

都是很基礎(chǔ)的配置哈,大概說(shuō)下邏輯.
當(dāng)我們?cè)诿钚休斎雗pm run build的時(shí)候,會(huì)執(zhí)行webpack.prod.js文件,
在prod配置文件里,借助merge插件,會(huì)把webpack.common.js里的配置也執(zhí)行起來(lái).
在common文件里,入口是main.js,打包出口是dist目錄
這時(shí)候我們執(zhí)行run build 應(yīng)該會(huì)看到新增加了一個(gè)目錄,如圖所示

image.png

5.根據(jù)業(yè)務(wù)需求配置插件

我們的目標(biāo)是搭建一個(gè)類似vue-cli的腳手架,所以我們需要如下插件

vue-loader

loader 用于對(duì)模塊的源代碼進(jìn)行轉(zhuǎn)換,vue-loader當(dāng)然就是對(duì)vue代碼進(jìn)行轉(zhuǎn)換,讓瀏覽器能夠識(shí)別.
vue-loader除了在rules里配置外,還要在plugins配置下,是為了把其他定義的規(guī)則應(yīng)用到vue文件里.

npm install vue@next -S
npm install vue-loader@next @vue/compiler-sfc

webpack.common.js文件:

const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')

module.exports = env =>{
    return {
        entry:'./src/main.js',//入口文件
        output:{
            filename: 'assets/js/[name].code.js',
            chunkFilename: 'assets/js/[name].bundle.js',//動(dòng)態(tài)導(dǎo)入 分離bundle 比如lodashjs配合注釋import(/* webpackChunkName: "lodash" */ 'lodash') 會(huì)打包成lodash.bundle.js
            path: path.resolve(__dirname, '../dist'),
        },
        plugins:[
            new VueLoaderPlugin()
        ],
        module:{
            rules:[
                {
                    test:/\.vue$/,
                    loader:'vue-loader'
                },
                // 它會(huì)應(yīng)用到普通的 `.js` 文件以及 `.vue` 文件中的 `<script>` 塊
            ]
        }
    }
}

HtmlWebpackPlugin

HtmlWebpackPlugin可以讓打包后的JS自動(dòng)引入html文件中

npm i -D html-webpack-plugin

這個(gè)插件也屬于生產(chǎn)和開發(fā)環(huán)境都用到的,所以在webpack.common.js文件里配置

const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = env =>{
    return {
        entry:'./src/main.js',//入口文件
        output:{
            filename: 'assets/js/[name].code.js',
            chunkFilename: 'assets/js/[name].bundle.js',//動(dòng)態(tài)導(dǎo)入 分離bundle 比如lodashjs配合注釋import(/* webpackChunkName: "lodash" */ 'lodash') 會(huì)打包成lodash.bundle.js
            path: path.resolve(__dirname, '../dist'),
        },
        plugins:[
            new VueLoaderPlugin(),
            new HtmlWebpackPlugin({
                template: path.join(__dirname, '../public/index.html'),
                filename: 'index.html',//輸出的文件名
            }),
        ],
        module:{
            rules:[
                {
                    test:/\.vue$/,
                    loader:'vue-loader'
                },
                // 它會(huì)應(yīng)用到普通的 `.js` 文件以及 `.vue` 文件中的 `<script>` 塊
            ]
        }
    }
}

bable-loader

這個(gè)就不多介紹了,能讓你現(xiàn)在就用ES6 7 8的語(yǔ)法,官方教程

npm install -D babel-loader @babel/core @babel/preset-env webpack

在webpack.common.js的rules里添加一條

module: {
      rules: [
        {
          test: /\.vue$/,
          loader: "vue-loader",
        }, // 它會(huì)應(yīng)用到普通的 `.js` 文件以及 `.vue` 文件中的 `<script>` 塊
        {
          test: /\.m?js$/,
          exclude: /(node_modules|bower_components)/,
          use: {
            loader: "babel-loader",
            options: {
              presets: ["@babel/preset-env"],
            },
          },
        },
      ],
    },

resolve

resolve主要是配置如何解析模塊.常用的有兩個(gè)extensions和alias,一個(gè)配置支持的后綴名.一個(gè)配置支持別名,不用逐層引入
在webpack.common.js文件里配置

resolve:{  //配置模塊如會(huì)解析
       extensions:['.vue','.js','.json'],//引入這些文件 可以不帶后綴 按順序解析
       alias:{
           '@':join('../src'), //@方式引入資源
       }
    },
image.png

資源模塊

資源模塊比如png svg jpg等圖片或者txt等,webpack5之前都是用file-loader或者url-loader來(lái)處理.
webpack5現(xiàn)在會(huì)自動(dòng)處理,不用再手動(dòng)配置.小于8kb的資源視為inline資源處理,否則視為resource處理.
比如如果我們想規(guī)定小于6kb的圖片才內(nèi)聯(lián)inline處理,否則就resource 引入.
webpack.common.js里

 {
            test: /\.(png|svg|jpg|gif)$/,
            type: 'asset',
            parser: {
               dataUrlCondition: {
                   maxSize: 6 * 1024,//小于6kb的圖片內(nèi)聯(lián)處理
               }
            }
        } 

5.開發(fā)環(huán)境配置

上面主要是webpack.common.js基礎(chǔ)配置,下面我們根據(jù)開發(fā)環(huán)境定制需要的配置.

friendly-errors-webpack-plugin

執(zhí)行npm run serve成功之后,可以在控制臺(tái)輸出信息

const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
const FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin");
const ip = require("ip");

let port = "8082";

module.exports = (env) => {
  let dev_config = {
    devtool: 'inline-source-map',//開啟source map
    mode: "development",
    plugins: [
      //運(yùn)行成功常空,輸出信息
      new FriendlyErrorsPlugin({
        compilationSuccessInfo: {
          messages: [
            `You application is running here http://${ip.address()}:${port} \r\nYou can also open local address http://localhost:${port}`,
          ],
          clearConsole: true,
        },
      }),
    ],
  };

  return merge(common(env), dev_config);
};

devserve

在devserve里我們可以指定端口啊,是否支持https,是否打開瀏覽器窗口.
webpack5的devserve和webpack4的devserve變化挺大,
如果有devserve定制需求,建議去官網(wǎng)看下,不能盲目粘貼過(guò)來(lái)
在plugins下面增加一個(gè)同級(jí)的配置即可.

 devServer: {
      host: "0.0.0.0",
      port: port,
      open:"http://localhost:" + port,//打開指定窗口
      proxy: {
        "/api": {
          target: "http://www.xxx.com:8080/api",
          secure: true, // 如果是https接口如叼,需要配置這個(gè)參數(shù)
          changeOrigin: true,
          pathRewrite: { "^/finchinaAPP": "" },
        },
      },
    },

cache

cache緩存生成的webpack模塊和chunk,主要用來(lái)提升構(gòu)建速度.
只在開發(fā)模式能用,默認(rèn)是memory既緩存到內(nèi)存中.
如果想自定義緩存策略,需要把cache的type值由memory改成filesystem.
比如修改默認(rèn)緩存目錄

const path = require('path');

module.exports = {
  //...
  cache: {
    type: 'filesystem',
    cacheDirectory: path.resolve(__dirname, '.temp_cache'),
  },
};

css處理

因?yàn)樯a(chǎn)環(huán)境的CSS需要壓縮,這里還是分別配置好了.
先安裝style-loader 把CSS插入到DOM中.

npm install --save-dev style-loader

再安裝css-loader 對(duì) @importurl() 進(jìn)行處理抛蚁,就像 js 解析 import/require() 一樣.

npm install --save-dev css-loader

最后在module的rules里增加一條規(guī)則

{
          //解析器的執(zhí)行順序是從下往上(先css-loader再style-loader)
          test: /\.css$/i,
          use: [
            "style-loader",
            {
              loader: "css-loader",
              options: {
                esModule: false,
                modules: {
                  auto: false, //modules 開關(guān),移動(dòng)端多頁(yè)面模式關(guān)閉class hash命名
                  localIdentName: "[local]_[hash:base64:8]", // 自定義生成的類名
                },
              },
            },
          ],
        },

sass-css處理

一般項(xiàng)目都會(huì)用到css處理器,所以光處理css是不夠的,假如項(xiàng)目用的是sass-css,這么解決.
安裝node-sass sass-loader

npm i node-sass -D
npm install sass-loader sass webpack --save-dev

在rulues里新增一個(gè)規(guī)則

 {
        test: /.s[ac]ss$/i,
        use: [
          // 將 JS 字符串生成為 style 節(jié)點(diǎn)
          'style-loader',
          // 將 CSS 轉(zhuǎn)化成 CommonJS 模塊
          'css-loader',
          // 將 Sass 編譯成 CSS
          'sass-loader',
        ],
      },

less-css處理

如果用的是less-css 需要安裝一個(gè)less-loader

npm install less less-loader --save-dev

然后在rules里配置下,這里沒(méi)有按照l(shuí)ess-loader的官網(wǎng)教程配置,因?yàn)閳?bào)引入錯(cuò)誤,可能文檔沒(méi)更新.

 {
          test: /\.less$/i,
          use: [
            // compiles Less to CSS
            "style-loader",
            "css-loader",
            "less-loader",
          ],
        },

到此,我們的開發(fā)環(huán)境就配置完了.

6.生產(chǎn)環(huán)境配置

webpack5相對(duì)于4自動(dòng)化增強(qiáng)了,比如會(huì)自動(dòng)清除輸出目錄下的歷史文件,自動(dòng)壓縮JS等.
css-loader sass-loader less-loader上面已經(jīng)介紹過(guò)了就不多介紹了.

提取css

借助MiniCssExtractPlugin插件

npm install --save-dev mini-css-extract-plugin

然后在plugins和css loader配置

plugins: [        
            new webpack.DefinePlugin({
                'process.env.NODE_ENV': JSON.stringify('production')
            }),

            //提取CSS
            new MiniCssExtractPlugin({
                filename:`assets/css/[name].style.css`,
                chunkFilename:`assets/css/[name].css`
            }),
        ],
        module: {
            rules: [
                {
                    //解析器的執(zhí)行順序是從下往上(先css-loader再style-loader)
                    test: /\.css$/,
                    use: [
                        MiniCssExtractPlugin.loader,
                        {
                            loader: 'css-loader',
                            options: {
                                esModule: false,
                                modules:{
                                    auto:false,//modules 開關(guān),移動(dòng)端多頁(yè)面模式關(guān)閉class hash命名
                                    localIdentName: '[local]_[hash:base64:8]',// 自定義生成的類名
                                }
                            }
                        },
                    ]
                },
                {
                    test: /\.scss$/,
                    use: [
                        MiniCssExtractPlugin.loader,
                        'css-loader',
                        'sass-loader'
                    ]
                },
                {
                    test: /\.less$/,
                    use: [
                        MiniCssExtractPlugin.loader,                    
                        'css-loader',
                        'less-loader'
                    ]
                },
            ]
        },

壓縮css

webpack4使用的是OptimizeCSSAssetsPlugin,到了webpack5官方推薦使用CssMinimizerWebpackPlugin

 npm install css-minimizer-webpack-plugin --save-dev

然后在module同級(jí)新增一個(gè)配置

optimization: {
    minimizer: [
      // 在 webpack@5 中询刹,你可以使用 `...` 語(yǔ)法來(lái)擴(kuò)展現(xiàn)有的 minimizer(即 `terser-webpack-plugin`)您旁,將下一行取消注釋
      // `...`,
      new CssMinimizerPlugin(),
    ],
  }

其實(shí)我們生產(chǎn)環(huán)境可以直接配置minimize: true,也行.

代碼分離Optimization

Optimization,webpack5默認(rèn)的構(gòu)建目標(biāo)是web.
如果是別的比如node項(xiàng)目或者electorn項(xiàng)目,需要增加一個(gè)target屬性
比如構(gòu)建node環(huán)境

module.exports = {
  target: 'node',
};

對(duì)于webpack的optimization,一般關(guān)注optimization.splitChunks多一些,
splitChunks默認(rèn)給我們配置了一套拆分規(guī)則

-   新的 chunk 可以被共享,或者模塊來(lái)自于 `node_modules` 文件夾
-   新的 chunk 體積大于 20kb(在進(jìn)行 min+gz 之前的體積)
-   當(dāng)按需加載 chunks 時(shí)锦募,并行請(qǐng)求的最大數(shù)量小于或等于 30
-   當(dāng)加載初始化頁(yè)面時(shí)逛拱,并發(fā)請(qǐng)求的最大數(shù)量小于或等于 30

optimization: {
    splitChunks: {
      chunks: 'async',
      minSize: 20000,
      minRemainingSize: 0,
      minChunks: 1,
      maxAsyncRequests: 30,
      maxInitialRequests: 30,
      enforceSizeThreshold: 50000,
      cacheGroups: {
        defaultVendors: {
          test: /[\/]node_modules[\/]/,
          priority: -10,
          reuseExistingChunk: true,
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },
}

我們也可以根據(jù)實(shí)際項(xiàng)目情況,做些調(diào)整,比如默認(rèn)20kb開始分割代碼,改成30KB分割代碼等

splitChunks: {
                minChunks: 2,  //模塊至少使用次數(shù)
                cacheGroups: {
                    vendor: {
                        name: 'vendor',
                        test: /[\\/]node_modules[\\/]/,
                        chunks: 'all',
                        priority: 2,  //2>0  nodulesmodules里的模塊將優(yōu)先打包進(jìn)vendor
                    },
                    commons: {
                        name: "commons",   //async異步代碼分割 initial同步代碼分割 all同步異步分割都開啟
                        chunks: "all",
                        minSize: 30000,         //字節(jié) 引入的文件大于30kb才進(jìn)行分割    
                        priority: 0,   //優(yōu)先級(jí)湿滓,先打包到哪個(gè)組里面滴须,值越大,優(yōu)先級(jí)越高
                    }
                }
            }

我們一般說(shuō)優(yōu)化項(xiàng)目,除了開源插件按需引入比如echarts,antdvue等,主要的是通過(guò)調(diào)整optimization的不同配置來(lái)優(yōu)化打包效果.想深入研究webpack優(yōu)化,建議多看看這個(gè).

打包體積分析

打包后的代碼,有時(shí)候文件比較大,需要分析下情況,這時(shí)候需要安裝分析插件webpack-bundle-analyzer

npm install --save-dev webpack-bundle-analyzer

然后配置只有監(jiān)聽(tīng)到輸入分析命令后才啟動(dòng),不然每次打包都要啟動(dòng)


image.png

然后在package.json配置啟動(dòng)命令

"scripts": {
    "serve": "webpack-dev-server  --hot   --config build/webpack.dev.js",
    "dev": "webpack-dev-server --open --progress --config build/webpack.dev.js",
    "build": "webpack  --config  build/webpack.prod.js",
    "distanalyzer": "webpack --env.analyzer=true --config build/webpack.prod.js"
  },

至此,大功搞定.

7.跑起來(lái)試一下

安裝vue-router

npm install vue-router@4

簡(jiǎn)單寫兩個(gè)頁(yè)面,成功!

image.png

具體代碼已經(jīng)放到GitHub上,點(diǎn)擊這里.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末叽奥,一起剝皮案震驚了整個(gè)濱河市扔水,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌朝氓,老刑警劉巖魔市,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異赵哲,居然都是意外死亡待德,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門枫夺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)将宪,“玉大人,你說(shuō)我怎么就攤上這事橡庞〗咸常” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵扒最,是天一觀的道長(zhǎng)丑勤。 經(jīng)常有香客問(wèn)我,道長(zhǎng)扼倘,這世上最難降的妖魔是什么确封? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任除呵,我火速辦了婚禮再菊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘颜曾。我一直安慰自己纠拔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布泛豪。 她就那樣靜靜地躺著稠诲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诡曙。 梳的紋絲不亂的頭發(fā)上臀叙,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音价卤,去河邊找鬼劝萤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛慎璧,可吹牛的內(nèi)容都是我干的床嫌。 我是一名探鬼主播跨释,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼厌处!你這毒婦竟也來(lái)了鳖谈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤阔涉,失蹤者是張志新(化名)和其女友劉穎缆娃,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體瑰排,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡龄恋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凶伙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片郭毕。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖函荣,靈堂內(nèi)的尸體忽然破棺而出显押,到底是詐尸還是另有隱情,我是刑警寧澤傻挂,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布乘碑,位于F島的核電站,受9級(jí)特大地震影響金拒,放射性物質(zhì)發(fā)生泄漏兽肤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一绪抛、第九天 我趴在偏房一處隱蔽的房頂上張望资铡。 院中可真熱鬧,春花似錦幢码、人聲如沸笤休。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)店雅。三九已至,卻和暖如春贞铣,著一層夾襖步出監(jiān)牢的瞬間闹啦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工辕坝, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窍奋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像费变,于是被迫代替她去往敵國(guó)和親摧扇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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