這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

平時大家開發vue專案的時候,相信大部分人都是使用 vue-cli腳手架生成的專案架構,然后 npm run install 安裝依賴,npm run serve啟動專案然后就開始寫業務代碼了,
但是對專案里的webpack封裝和配置了解的不清楚,容易導致出問題不知如何解決,或者不會通過webpack去擴展新功能,
該篇文章主要是想告訴兄弟們,如何一步一步的通過 webpack4來搭建自己的vue開發環境
首先我們要知道 vue-cli生成的專案,幫我們配置好了哪些功能?
ES6代碼轉換成ES5代碼scss/sass/less/stylus轉css.vue檔案轉換成js檔案- 使用
jpg、png,font等資源檔案 - 自動添加css各瀏覽器產商的前綴
- 代碼熱更新
- 資源預加載
- 每次構建代碼清除之前生成的代碼
- 定義環境變數
- 區分開發環境打包跟生產環境打包
- ....
1. 搭建 webpack 基本環境
該篇文章并不會細講 webpack 是什么東西,如果還不是很清楚的話,可以先去看看 webpack官網
簡單的說,webpack是一個模塊打包機,可以分析你的專案依賴的模塊以及一些瀏覽器不能直接運行的語言jsx、vue等轉換成 js、css檔案等,供瀏覽器使用,
1.1 初始化專案
在命令列中執行 npm init 然后一路回車就行了,主要是生成一些專案基本資訊,最后會生成一個 package.json 檔案
npm init
1.2 安裝webpack

1.3 寫點小代碼測驗一下webpack是否安裝成功了
新建一個src檔案夾,然后再建一個main.js檔案
// src/main.js
console.log('hello webpack')
然后在 package.json 下面加一個腳本命令

然后運行該命令
npm run serve
如果在 dist 目錄下生成了一個main.js檔案,則表示webpack作業正常
2. 開始配置功能
- 新建一個
build檔案夾,用來存放webpack配置相關的檔案 - 在
build檔案夾下新建一個webpack.config.js,配置webpack的基本配置 - 修改
webpack.config.js配置

- 修改
package.json檔案,將之前添加的serve修改為
"serve": "webpack ./src/main.js --config ./build/webpack.config.js"
2.1 配置 ES6/7/8 轉 ES5代碼
- 安裝相關依賴
npm install babel-loader @babel/core @babel/preset-env
- 修改
webpack.config.js配置

- 在專案根目錄添加一個
babel.config.js檔案

- 然后執行
npm run serve命令,可以看到 ES6代碼被轉成了ES5代碼了
2.1.1 ES6/7/8 Api 轉es5
babel-loader只會將 ES6/7/8語法轉換為ES5語法,但是對新api并不會轉換,
我們可以通過 babel-polyfill 對一些不支持新語法的客戶端提供新語法的實作
- 安裝
npm install @babel/polyfill
- 修改
webpack.config.js配置
在 entry 中添加 @babel-polyfill

2.1.2 按需引入polyfill
2.1.2 和 2.1.1 只需要配置一個就行
修改時間 2019-05-05、 來自評論區 兮漫天 的提醒
- 安裝相關依賴
npm install core-js@2 @babel/runtime-corejs2 -S
- 修改 babel-config.js

配置了按需引入 polyfill 后,用到es6以上的函式,babel會自動匯入相關的polyfill,這樣能大大減少 打包編譯后的體積
2.2 配置 scss 轉 css
在沒配置 css 相關的 loader 時,引入scss、css相關檔案打包的話,會報錯
- 安裝相關依賴
npm install sass-loader dart-sass css-loader style-loader -D
sass-loader, dart-sass主要是將 scss/sass 語法轉為css
css-loader主要是決議 css 檔案
style-loader 主要是將 css 決議到 html頁面 的 style 上
- 修改
webpack.config.js配置

2.3 配置 postcss 實作自動添加css3前綴
- 安裝相關依賴
npm install postcss-loader autoprefixer -D
- 修改
webpack.config.js配置

- 在專案根目錄下新建一個
postcss.config.js

2.3 使用 html-webpack-plugin來創建html頁面
使用 html-webpack-plugin來創建html頁面,并自動引入打包生成的js檔案
- 安裝依賴
npm install html-webpack-plugin -D
- 新建一個 public/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>Document</title> </head> <body> <div id="app"></div> </body> </html>
- 修改
webpack-config.js配置

2.4 配置 devServer 熱更新功能
通過代碼的熱更新功能,我們可以實作不重繪頁面的情況下,更新我們的頁面
- 安裝依賴
npm install webpack-dev-server -D
- 修改
webpack.config.js配置
通過配置 devServer 和 HotModuleReplacementPlugin 插件來實作熱更新

2.5 配置 webpack 打包 圖片、媒體、字體等檔案
- 安裝依賴
npm install file-loader url-loader -D
file-loader 決議檔案url,并將檔案復制到輸出的目錄中
url-loader 功能與 file-loader 類似,如果檔案小于限制的大小,則會回傳 base64 編碼,否則使用 file-loader 將檔案復制到輸出的目錄中
- 修改
webpack-config.js配置 添加rules配置,分別對 圖片,媒體,字體檔案進行配置
// build/webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
module.exports = {
// 省略其它配置 ...
module: {
rules: [
// ...
{
test: /\.(jpe?g|png|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 4096,
fallback: {
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]'
}
}
}
}
]
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 4096,
fallback: {
loader: 'file-loader',
options: {
name: 'media/[name].[hash:8].[ext]'
}
}
}
}
]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 4096,
fallback: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[hash:8].[ext]'
}
}
}
}
]
},
]
},
plugins: [
// ...
]
}
3. 讓 webpack 識別 .vue 檔案
- 安裝需要的依賴檔案
npm install vue-loader vue-template-compiler cache-loader thread-loader -D npm install vue -S
vue-loader 用于決議.vue檔案
vue-template-compiler 用于編譯模板
cache-loader 用于快取loader編譯的結果
thread-loader 使用 worker 池來運行loader,每個 worker 都是一個 node.js 行程,
- 修改
webpack.config.js配置
// build/webpack.config.js
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
// 指定打包模式
mode: 'development',
entry: {
// ...
},
output: {
// ...
},
devServer: {
// ...
},
resolve: {
alias: {
vue$: 'vue/dist/vue.runtime.esm.js'
},
},
module: {
rules: [
{
test: /\.vue$/,
use: [
{
loader: 'cache-loader'
},
{
loader: 'thread-loader'
},
{
loader: 'vue-loader',
options: {
compilerOptions: {
preserveWhitespace: false
},
}
}
]
},
{
test: /\.jsx?$/,
use: [
{
loader: 'cache-loader'
},
{
loader: 'thread-loader'
},
{
loader: 'babel-loader'
}
]
},
// ...
]
},
plugins: [
// ...
new VueLoaderPlugin()
]
}
- 測驗一下
- 在 src 新建一個 App.vue
// src/App.vue
<template>
<div >
Hello World
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {};
}
};
</script>
<style lang="scss" scoped>
.App {
color: skyblue;
}
</style>
- 修改
main.js
import Vue from 'vue'
import App from './App.vue'
new Vue({
render: h => h(App)
}).$mount('#app')
- 運行一下
npm run serve
4. 定義環境變數
通過 webpack提供的DefinePlugin插件,可以很方便的定義環境變數
plugins: [
new webpack.DefinePlugin({
'process.env': {
VUE_APP_BASE_URL: JSON.stringify('http://localhost:3000')
}
}),
]
5. 區分生產環境和開發環境
新建兩個檔案
-
webpack.dev.js開發環境使用 -
webpack.prod.js生產環境使用 -
webpack.config.js公用配置 -
開發環境與生產環境的不同
5.1 開發環境
- 不需要壓縮代碼
- 需要熱更新
- css不需要提取到css檔案
- sourceMap
- ...
5.2 生產環境
- 壓縮代碼
- 不需要熱更新
- 提取css,壓縮css檔案
- sourceMap
- 構建前清除上一次構建的內容
- ...
- 安裝所需依賴
npm i @intervolga/optimize-cssnano-plugin mini-css-extract-plugin clean-webpack-plugin webpack-merge copy-webpack-plugin -D
@intervolga/optimize-cssnano-plugin用于壓縮css代碼mini-css-extract-plugin用于提取css到檔案中clean-webpack-plugin用于洗掉上次構建的檔案webpack-merge合并webpack配置copy-webpack-plugin用戶拷貝靜態資源
5.3 開發環境配置
- build/webpack.dev.js
// build/webpack.dev.js
const merge = require('webpack-merge')
const webpackConfig = require('./webpack.config')
const webpack = require('webpack')
module.exports = merge(webpackConfig, {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
module: {
rules: [
{
test: /\.(scss|sass)$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
{
loader: 'sass-loader',
options: {
implementation: require('dart-sass')
}
},
{
loader: 'postcss-loader'
}
]
},
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('development')
}
}),
]
})
- webpack.config.js
// build/webpack.config.js
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
entry: {
// 配置入口檔案
main: path.resolve(__dirname, '../src/main.js')
},
output: {
// 配置打包檔案輸出的目錄
path: path.resolve(__dirname, '../dist'),
// 生成的 js 檔案名稱
filename: 'js/[name].[hash:8].js',
// 生成的 chunk 名稱
chunkFilename: 'js/[name].[hash:8].js',
// 資源參考的路徑
publicPath: '/'
},
devServer: {
hot: true,
port: 3000,
contentBase: './dist'
},
resolve: {
alias: {
vue$: 'vue/dist/vue.runtime.esm.js'
},
extensions: [
'.js',
'.vue'
]
},
module: {
rules: [
{
test: /\.vue$/,
use: [
{
loader: 'cache-loader'
},
{
loader: 'vue-loader',
options: {
compilerOptions: {
preserveWhitespace: false
},
}
}
]
},
{
test: /\.jsx?$/,
loader: 'babel-loader'
},
{
test: /\.(jpe?g|png|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 4096,
fallback: {
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]'
}
}
}
}
]
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 4096,
fallback: {
loader: 'file-loader',
options: {
name: 'media/[name].[hash:8].[ext]'
}
}
}
}
]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 4096,
fallback: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[hash:8].[ext]'
}
}
}
}
]
},
]
},
plugins: [
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../public/index.html')
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
]
}
5.4 生產環境配置
const path = require('path')
const merge = require('webpack-merge')
const webpack = require('webpack')
const webpackConfig = require('./webpack.config')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssnanoPlugin = require('@intervolga/optimize-cssnano-plugin');
/* clean-webpack-plugin 3.0 以上的版本需要使用物件結構 */
// const CleanWebpackPlugin = require('clean-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = merge(webpackConfig, {
mode: 'production',
devtool: '#source-map',
optimization: {
splitChunks: {
cacheGroups: {
vendors: {
name: 'chunk-vendors',
test: /[\\\/]node_modules[\\\/]/,
priority: -10,
chunks: 'initial'
},
common: {
name: 'chunk-common',
minChunks: 2,
priority: -20,
chunks: 'initial',
reuseExistingChunk: true
}
}
}
},
module: {
rules: [
{
test: /\.(scss|sass)$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader',
options: {
importLoaders: 2
}
},
{
loader: 'sass-loader',
options: {
implementation: require('dart-sass')
}
},
{
loader: 'postcss-loader'
}
]
},
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: 'production'
}
}),
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].css'
}),
new OptimizeCssnanoPlugin({
sourceMap: true,
cssnanoOptions: {
preset: [
'default',
{
mergeLonghand: false,
cssDeclarationSorter: false
}
]
}
}),
new CopyWebpackPlugin([
{
from: path.resolve(__dirname, '../public'),
to: path.resolve(__dirname, '../dist')
}
]),
new CleanWebpackPlugin()
]
})
5.5 修改package.json
"scripts": {
"serve": "webpack-dev-server --config ./build/webpack.dev.js",
"build": "webpack --config ./build/webpack.prod.js"
},
6 打包分析
有的時候,我們需要看一下webpack打包完成后,到底打包了什么東西,
這時候就需要用到這個模塊分析工具了 webpack-bundle-analyzer
- 安裝依賴
npm install --save-dev webpack-bundle-analyzer
- 修改
webpack-prod.js配置,在plugins屬性中新增一個插件
在開發環境中,我們是沒必要進行模塊打包分析的,所以我們將插件配置在了生產環境的配置項中

- 運行打包命令
npm run build
執行成功后會自動打開這個頁面

7. 集成 VueRouter,Vuex
- 首先是安裝相關依賴
npm install vue-router vuex --save
7.1 集成 Vue-Router
- 新增視圖組件 在
src目錄下新增兩個視圖組件src/views/Home.vue和src/views/About.vue
// src/views/Home.vue
<template>
<div >
<h2>Home</h2>
</div>
</template>
<script>
export default {
name: 'Home',
data() {
return {};
}
};
</script>
<style lang="scss" scoped>
</style>
About.vue 內容跟 Home.vue 差不多,將里面的 Home 換成 About 就OK了
- 新增路由組態檔
在 src 目錄下新增一個 router/index.js 檔案
// src/router/index.js
import Vue from 'vue'
import VueRouter from "vue-router";
import Home from '../views/Home';
import About from '../views/About';
Vue.use(VueRouter)
export default new VueRouter({
mode: 'hash',
routes: [
{
path: '/Home',
component: Home
},
{
path: '/About',
component: About
},
{
path: '*',
redirect: '/Home'
}
]
})
- 修改
main.js檔案
// main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
new Vue({
router,
render: h => h(App)
}).$mount('#app')
- 修改
App.vue組件
// App.vue
// 在 template 中添加
// src/App.vue
<template>
<div >
Hello World
</div>
<div>
// router-link 組件 用來導航到哪個路由
<router-link to="/Home">go Home</router-link>
<router-link to="/About">go About</router-link>
</div>
<div>
// 用于展示匹配到的路由視圖組件
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {};
}
};
</script>
<style lang="scss" scoped>
.App {
color: skyblue;
}
</style>
運行 npm run serve 命令,如沒配置錯誤,是可以看到點擊不同的路由,會切換到不同的路由視圖
7.2 配置路由懶加載
在沒配置路由懶加載的情況下,我們的路由組件在打包的時候,都會打包到同一個js檔案去,當我們的視圖組件越來越多的時候,就會導致這個 js 檔案越來越大,然后就會導致請求這個檔案的時間變長,最終影響用戶體驗
- 安裝依賴
npm install @babel/plugin-syntax-dynamic-import --save-dev
- 修改
babel.config.js
module.exports = {
presets: [
[
"@babel/preset-env",
{
useBuiltIns: "usage"
}
]
],
plugins: [
// 添加這個
'@babel/plugin-syntax-dynamic-import'
]
}
- 修改
router/index.js路由組態檔
import Vue from 'vue'
import VueRouter from "vue-router";
Vue.use(VueRouter)
export default new VueRouter({
mode: 'hash',
routes: [
{
path: '/Home',
component: () => import(/* webpackChunkName: "Home" */ '../views/Home.vue')
// component: Home
},
{
path: '/About',
component: () => import(/* webpackChunkName: "About" */ '../views/About.vue')
// component: About
},
{
path: '*',
redirect: '/Home'
}
]
})
- 運行命令
npm run build查看是否生成了Home...js檔案 和About...js檔案
7.3 集成 Vuex
- 在
src目錄下新建一個store/index.js檔案
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
counter: 0
}
const actions = {
add: ({commit}) => {
return commit('add')
}
}
const mutations = {
add: (state) => {
state.counter++
}
}
const getters = {
getCounter (state) {
return state.counter
}
}
export default new Vuex.Store({
state,
actions,
mutations,
getters
})
- 修改
main.js檔案 匯入vuex
// main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store' // ++
new Vue({
router,
store, // ++
render: h => h(App)
}).$mount('#app')
- 修改
App.vue,查看 vuex 配置效果
// App.vue
<template>
<div >
<div>
<router-link to="/Home">go Home</router-link>
<router-link to="/About">go About</router-link>
</div>
<div>
<p>{{getCounter}}</p>
<button @click="add">add</button>
</div>
<div>
<router-view></router-view>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
export default {
name: 'App',
data() {
return {};
},
computed: {
...mapGetters(['getCounter'])
},
methods: {
...mapActions(['add'])
}
};
</script>
<style lang="scss" scoped>
.App {
text-align: center;
color: skyblue;
font-size: 28px;
}
</style>
- 運行命令
npm run serve
當點擊按鈕的時候,可以看到我們的getCounter一直在增加
8 總結
到目前為止,我們已經成功的自己搭建了一個 vue 開發環境,不過還是有一些功能欠缺的,有興趣的小伙伴可以交流交流,在搭建程序中,還是會踩很多坑的,
如果還不熟悉 webpack 的話,建議自己搭建一次,可以讓自己能深入的理解 vue-cli 替我們做了什么
專案代碼:github.com/lentoo/vue-…
本文轉載于:
https://juejin.cn/post/6844903833160646663
如果對您有所幫助,歡迎您點個關注,我會定時更新技術檔案,大家一起討論學習,一起進步,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/519309.html
標籤:其他
上一篇:$router.push({name:component})與$router.push(‘pathName’)的小區別
