vue-webpack
介紹 vue+webpack 手動搭建過程,熟悉 webpack 的配置,loader&插件的使用
介紹
目標:熟悉 webpack 的配置,loader&插件的使用
通常新建 vue 項目都使用 vue-cli 腳手架,其實對於 webpack 的配置是一知半解,當需要升級 webpack 或者優化項目配置時,就顯得很無力。通過手動搭建 webpack 可以對 webpack 有更深入的瞭解,當我們使用其他模塊管理器時(eg:rollup,gulp),也不會那麼生疏。
關於 dependencies 和 devDependencies
通過 NODE_ENV=developement 或 NODE_ENV=production 指定開發還是生產環境
devDependencies 是只會在開發環境下依賴的模塊,生產環境不會被打入包內。
而 dependencies 依賴的包不僅開發環境能使用,生產環境也能使用。其實這句話是重點,按照這個觀念很容易決定安裝模塊時是使用--save 還是--save-dev。
項目包版本
"dependencies": {
"@xunlei/vue-lazy-component": "^1.1.3",
"echarts": "^4.2.1",
"element-resize-event": "^3.0.3",
"element-ui": "^2.7.2",
"file-loader": "^4.0.0",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"intersection-observer": "^0.7.0",
"lodash": "^4.17.11",
"url-loader": "^2.0.0",
"vue": "^2.6.10",
"webpack": "^4.34.0"
}
遇到的配置錯誤
1.vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.
解決辦法:Vue-loader 在 15.*之後的版本都是 vue-loader 的使用都是需要伴生 VueLoaderPlugin 的
2.Entrypoint undefined = index.html 代碼不報錯但是頁面白版
解決辦法:webpcak.config.js 中
new HTMLPlugin({
template: 'index.html'
}),
3.Child html-webpack-plugin for "index.html": Entrypoint undefined = index.html
解決辦法:webpcak.config.js 中
resolve: {
alias: {
vue: 'vue/dist/vue.js'
}
},
這裏涉及到一個小知識點 編譯時&運行時
4.運行時 + 編譯器 vs. 只包含運行時
https://cn.vuejs.org/v2/guide...
因爲在 Vue.js 2.0 中,最終渲染都是通過 render 函數,如果寫 template 屬性,則需要編譯成 render 函數,那麼這個編譯過程會發生運行時,所以需要帶有編譯器的版本。很顯然,這個編譯過程對性能會有一定損耗,所以通常我們更推薦使用 Runtime-Only 的 Vue.js。
只有以下情況會用到 compiler: 1.有指定 template; 2.沒指定 template,也沒指定 render(這時候使用的就是被掛載元素的 outerHtml)。
所以,沒有使用到 compiler 的情況只有:沒有指定 template,但指定了 render。
有時會遇到這樣的錯誤:[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
以上提到,解決這個問題有兩種方式,但大多會選擇後者,也就是使用全功能的 vue(runtime+compiler),這個版本的 vue 文件相比僅包含 runtime 的版本體積要大,而且運行時的 compiler 轉換會消耗性能,compiler 過程其實可以放到構建過程中進行。總結就是,如果可以的話,儘量使用 runtime 版的 vue 文件。
5. It's no longer allowed to omit the '-loader' suffix when using loaders.
Webpack 新版本要求配置 module 中的 loader 不能縮寫,也就是
loader:"json-loader"
中的-loader 必須要寫。
(在網上找配置時需要注意)
搭建步驟
1.生成 package.json
npm init
2.安裝依賴
npm i webpack vue vue-loader
npm i css-loader vue-template-compiler
3.文件目錄
新建 app.vue
<template>
<div id="test">{{text}}</div>
</template>
<script>
export default {
data() {
return {
text: 'abc'
}
}
}
</script>
<style>
#test {
color: red;
}
</style>
新建入口文件 index.js
import Vue from 'vue'
import App from './app.vue'
// Runtime Only
// new Vue({
// render: h => h(App) //h就是vue中的createApp參數
// }).$mount('#app') //將app掛載到body下的div上
// 會用到 compiler 所以使用全功能的 vue
new Vue({
el: '#app',
components: { App },
template: '<App/>'
})
新建 webpack.config.js 配置
const path = require('path') //nodeJs的基本包
module.exports = {
//path.join(__dirname, 'src/index.js')中__dirname表示當前文件的路徑,path.join就是將當前文件的路徑跟'src/index.js'拼接起來,形成一個絕對路徑
entry: path.join(__dirname, 'src/index.js'),
//輸出文件,取名爲bundle.js,路徑爲dist文件夾
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'dist')
},
module: {
rules: [
{
test: /.vue$/,
loader: 'vue-loader'
}
]
}
}
修改 package.json 文件
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.config.js"
}
webpack 配置項目加載各種靜態資源及 css 預處理器
其中 index.js 入口文件如下:
import './assets/css/global.css'
其中 webpack.config.js 如下:
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.html$/i,
loader: 'html-loader'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.(gif|jpg|jpeg|png|svg)$/,
use: [
{
loader: 'url-loader', //能夠將圖片轉成base64代碼直接寫在js裏面,依賴file-loader,所以在安裝的時候不僅要裝url-loader還要裝file-loader
options: {
limit: 1024, //如果文件大小小於1024字節,就會轉義成base64,否則仍然是圖片
name: '[name]-aaa.[ext]' //輸出文件的名字,name就是原先圖片的名字,-aaa是自己家的字段
}
}
]
}
]
},
webpack-dev-server 的配置和使用
- 先在 package.json 中的 script 中加一個命令"dev":“webpack-dev-server --config webpack.config.js”
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
"dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"
}
cross-env 能跨平臺地設置及使用環境變量
npm 安裝方式
npm i --save-dev cross-env
在 npm 腳本(多是 package.json)裏這麼配置
"scripts": {
"build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
}
運行 npm run build,這樣 NODE_ENV 便設置成功,無需擔心跨平臺問題
- 修改 webpack 設置,來專門適應我們的 webpack-dev-server 的開發模式
- 添加 webpack 的編譯目標 target 爲 web
- 添加變量 isDev,用於讀取是否爲 development 環境。
- 需要一個 html,去容納我們的 js 文件,不然沒有 html,我們的項目是不能在瀏覽器中顯示的html-webpack-plugin 詳細用法
- devServer 中,還有其他的配置
1.historyFallback 對於非定義的路由的處理
2.open: true,//啓動的時候,自動打開瀏覽器
3.hot: true,//熱加載,不需要刷新頁面就能加載出來 - 當使用熱加載時還需要添加插件
1.new webpack.HotModuleReplacementPlugin()
2.new webpack.NoEmitOnErrorsPlugin()//減少我們不需要的信息的展示 - source-map 的配置
config.devtool = '#cheap-module-eval-source-map';
所以,整個 webpack 的代碼爲:
const path = require('path')
const HTMLPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const webpack = require('webpack')
const isDev = process.env.NODE_ENV === 'development'
const config = {
target: 'web',
entry: path.join(__dirname, 'src/index.js'),
output: {
filename: 'dist/bundle.js',
path: path.join(__dirname, 'dist')
},
resolve: {
alias: {
vue$: 'vue/dist/vue.esm.js' // 用 webpack 1 時需用 'vue/dist/vue.common.js'
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.html$/i,
loader: 'html-loader'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.(gif|jpg|jpeg|png|svg)$/,
use: [
{
loader: 'url-loader', //能夠將圖片轉成base64代碼直接寫在js裏面,依賴file-loader,所以在安裝的時候不僅要裝url-loader還要裝file-loader
options: {
limit: 1024, //如果文件大小小於1024字節,就會轉義成base64,否則仍然是圖片
name: '[name]-aaa.[ext]' //輸出文件的名字,name就是原先圖片的名字,-aaa是自己家的字段
}
}
]
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: isDev ? '"development"' : '"production"'
}
}), //一般vue、react等框架都要用到這個插件。
//在這裏定義了,在我們的js代碼中是可以引用到的。
//現在,veu/react這類框架會根據環境去區分打包,打包後的dist在開發環境中是比較大的,因爲有很多類似錯誤的信息們可以幫助我們開發人員開發,而生產環境是比較小的,沒有繁多的錯誤信息,我們也不希望錯誤信息給用戶看,所以就沒必要把錯誤信息打包進去了
//爲什麼單引號裏面還要雙引號?因爲如果沒有的話,調用的時候,就成了process.env.NODE_ENV = development,這時候development就成了一個變量,所以需要寫上雙引號
new HTMLPlugin({
template: 'index.html'
}),
new VueLoaderPlugin()
]
}
if (isDev) {
config.devtool = '#cheap-module-eval-source-map' //幫助我們在頁面上調試我們的代碼的,並且有很多種source-map的映射方式,不同映射方式有不同的優缺點,這裏寫的只是其中一種,這個值,可以讓你在瀏覽器看到源碼
config.devServer = {
port: 8088,
host: 'localhost', //可以通過localhost,127.0.0.1,本機的內網IP進行訪問(IP的話,就可以在別人的電腦上訪問)
overlay: {
error: true //如果編譯有錯誤,就直接顯示在網頁上
},
open: true,
hot: true //熱加載,不需要刷新頁面就能加載出來
}
config.plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin() //減少我們不需要的信息的展示
)
}
module.exports = config
webpack 指定 mode
這部分厲害了,看完文檔就知道爲什麼使用 vue-cli 腳手架 vue init webpack [項目名]生成的 webpack 配置文件包含
;-build | -webpack.base.conf.js | -webpack.base.dev.js | -webpack.base.prod.js
配置
development(開發環境) 和 production(生產環境) 這兩個環境下的構建目標存在着巨大差異。
- 開發環境中:強大的 source map 和一個有着 live reloading(實時重新加載) 或 hot module replacement(熱模塊替換) 能力的 localhost server
- 生產環境:關注點在於壓縮 bundle、更輕量的 source map、資源優化等,通過這些優化方式改善加載時間。
我們先從安裝 webpack-merge 開始,並將已經成型的那些代碼進行分離:
npm install --save-dev webpack-merge
- |- webpack.config.js
+ |- webpack.common.js
+ |- webpack.dev.js
+ |- webpack.prod.js
具體使用方式查看文檔webpack 指定 mode
生產環境性能優化
1.html-webpack-plugin
該插件將爲你生成一個 HTML5 文件, 其中包括使用 script 標籤的 body 中的所有 webpack 包。
new HTMLPlugin({
template: 'index.html',
minify: {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
useShortDoctype: true
}
}),
針對生成的 html 移除註釋、刪除空行、html 壓縮等操作
2.mini-css-extract-plugin
將 CSS 提取爲獨立的文件的插件
查看文件中 webpack.config.js 配置
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// 類似 webpackOptions.output裏面的配置 可以忽略
filename: '[name].css',
chunkFilename: '[id].css',
}),
],
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
isDev ? 'sass-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
},
]
}
}
測試 css 被單獨提取,文件大小爲 main.css 264K
階段進行壓縮
webpack5 可能會內置 CSS 壓縮器,webpack4 需要自己使用壓縮器,可以使用 optimize-css-assets-webpack-plugin 插件。 設置 optimization.minimizer 覆蓋 webpack 默認提供的,確保也指定一個 JS 壓縮器
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourcMap: true
}),
new OptimizeCSSAssetsPlugin({}),
],
}
測試 css 被單獨提取,文件大小爲 main.css 219K 比壓縮前減少 45K
3.uglifyjs-webpack-plugin
遇到的錯誤
ERROR in bundle.js from UglifyJs
Unexpected token: punc «(» src/app.vue:21,0
解決方法: 配置 babel
未使用前 bundle.js 1937KB 使用後壓縮到 752KB
4.CompressionPlugin
當我們的項目越來越龐大是時候 會發現 即使做了 code split 代碼壓縮 動態加載 等等一系列優化之後 頁面的響應速度依舊很慢
這個時候時候可以使用 compression-webpack-plugin 這個插件
new CompressionPlugin({
"filename": "[path].gz[query]",
"test": new RegExp(
"\\.(js|css)$" //壓縮 js 與 css
),
"threshold": 500, // 當文件超過限制大小 使用gzip
"minRatio": 0.8,
"algorithm": "gzip"
})
該插件的作用是 在超過限定的文件大小的 時候會生成一個跟文件同名的 gz 包,這個時候我們需要在改下 nginx 的配置 啓用 gzip 壓縮並 開啓 gzip_static
vendors~main.772d21ef3139973e4cab.bundle.js.gz 可以將原來 819KB 壓縮到 220KB 壓縮力度還是非常大的
參考(特別感謝)
- 你真的理解 devDependencies 和 dependencies 區別嗎?
- webpack 中文文檔
- vue 編譯時運行時
- 瞭解 vue 裏的 Runtime Only 和 Runtime+Compiler
- It’s no longer allowed to omit the ‘-loader’ suffix
- vue 項目從 0 搭建(webpack 手動搭建)
- webpack4 mini-css-extract-plugin
- MiniCssExtractPlugin 需要添加 babel
- webpack-bundle-analyzer 打包文件分析工具
- SplitChunksPlugin
- Webpack SplitChunksPlugin 的三種模式
- 基於 vue2.x 的 webpack4 配置(生產環境~)
- vue 進行 gzip 壓縮和服務器如何開啓 gzip)
- web 應用性能優化之 nginx + compression-webpack-plugin