摘要:在搭建過程中,還是會踩很多坑的。如果還不熟悉的話,建議自己搭建一次。
開篇原文地址:www.ccode.live/lentoo/list…
前段時間,看到群里一些小伙伴面試的時候被面試官問到這類題目。平時大家開發(fā)vue項目的時候,相信大部分人都是使用 vue-cli腳手架生成的項目架構(gòu),然后 npm run install 安裝依賴,npm run serve啟動項目然后就開始寫業(yè)務(wù)代碼了。
但是對項目里的webpack封裝和配置了解的不清楚,容易導(dǎo)致出問題不知如何解決,或者不會通過webpack去擴(kuò)展新功能。
該篇文章主要是想告訴小伙伴們,如何一步一步的通過 webpack4來搭建自己的vue開發(fā)環(huán)境
首先我們要知道 vue-cli生成的項目,幫我們配置好了哪些功能?
ES6代碼轉(zhuǎn)換成ES5代碼
scss/sass/less/stylus轉(zhuǎn)css
.vue文件轉(zhuǎn)換成js文件
使用 jpg、png,font等資源文件
自動添加css各瀏覽器產(chǎn)商的前綴
代碼熱更新
資源預(yù)加載
每次構(gòu)建代碼清除之前生成的代碼
定義環(huán)境變量
區(qū)分開發(fā)環(huán)境打包跟生產(chǎn)環(huán)境打包
....
1. 搭建 webpack 基本環(huán)境
該篇文章并不會細(xì)講 webpack 是什么東西,如果還不是很清楚的話,可以先去看看 webpack官網(wǎng)
簡單的說,webpack是一個模塊打包機(jī),可以分析你的項目依賴的模塊以及一些瀏覽器不能直接運行的語言jsx、vue等轉(zhuǎn)換成 js、css文件等,供瀏覽器使用。
1.1 初始化項目
在命令行中執(zhí)行 npm init 然后一路回車就行了,主要是生成一些項目基本信息。最后會生成一個 package.json 文件
npm init1.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配置相關(guān)的文件
在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 轉(zhuǎn) ES5代碼
安裝相關(guān)依賴
npm install babel-loader @babel/core @babel/preset-env
修改webpack.config.js配置
在項目根目錄添加一個 babel.config.js 文件
然后執(zhí)行 npm run serve 命令,可以看到 ES6代碼被轉(zhuǎn)成了ES5代碼了
babel-loader只會將 ES6/7/8語法轉(zhuǎn)換為ES5語法,但是對新api并不會轉(zhuǎn)換。
我們可以通過 babel-polyfill 對一些不支持新語法的客戶端提供新語法的實現(xiàn)
安裝
npm install @babel/polyfill
修改webpack.config.js配置
在 entry 中添加 @babel-polyfill
2.1.2 和 2.1.1 只需要配置一個就行
修改時間 2019-05-05、 來自評論區(qū) 兮漫天 的提醒
安裝相關(guān)依賴
npm install core-js@2 @babel/runtime-corejs2 -S
修改 babel-config.js
配置了按需引入 polyfill 后,用到es6以上的函數(shù),babel會自動導(dǎo)入相關(guān)的polyfill,這樣能大大減少 打包編譯后的體積
2.2 配置 scss 轉(zhuǎn) css在沒配置 css 相關(guān)的 loader 時,引入scss、css相關(guān)文件打包的話,會報錯
安裝相關(guān)依賴
npm install sass-loader dart-sass css-loader style-loader -D
sass-loader, dart-sass主要是將 scss/sass 語法轉(zhuǎn)為css
css-loader主要是解析 css 文件
style-loader 主要是將 css 解析到 html頁面 的 style 上
修改webpack.config.js配置
2.3 配置 postcss 實現(xiàn)自動添加css3前綴
安裝相關(guān)依賴
npm install postcss-loader autoprefixer -D
修改webpack.config.js配置
在項目根目錄下新建一個 postcss.config.js
2.3 使用 html-webpack-plugin來創(chuàng)建html頁面
使用 html-webpack-plugin來創(chuàng)建html頁面,并自動引入打包生成的js文件
安裝依賴
npm install html-webpack-plugin -D
新建一個 public/index.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>Documenttitle>
head>
<body>
<div id="app">div>
body>
html>
修改 webpack-config.js 配置
2.4 配置 devServer 熱更新功能通過代碼的熱更新功能,我們可以實現(xiàn)不刷新頁面的情況下,更新我們的頁面
安裝依賴
npm install webpack-dev-server -D
修改webpack.config.js配置
通過配置 devServer 和 HotModuleReplacementPlugin 插件來實現(xiàn)熱更新
2.5 配置 webpack 打包 圖片、媒體、字體等文件
安裝依賴
npm install file-loader url-loader -D
file-loader 解析文件url,并將文件復(fù)制到輸出的目錄中
url-loader 功能與 file-loader 類似,如果文件小于限制的大小。則會返回 base64 編碼,否則使用 file-loader 將文件復(fù)制到輸出的目錄中
修改 webpack-config.js 配置 添加 rules 配置,分別對 圖片,媒體,字體文件進(jìn)行配置
// build/webpack.config.js
const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const webpack = require("webpack")
module.exports = {
// 省略其它配置 ...
module: {
rules: [
// ...
{
test: /.(jpe");,
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");,
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編譯的結(jié)果
thread-loader 使用 worker 池來運行loader,每個 worker 都是一個 node.js 進(jìn)程。
修改 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"App"> Hello World
修改 main.js
import Vue from "vue"
import App from "./App.vue"
new Vue({
render: h => h(App)
}).$mount("#app")
運行一下
npm run serve
4. 定義環(huán)境變量通過 webpack提供的DefinePlugin插件,可以很方便的定義環(huán)境變量
plugins: [
new webpack.DefinePlugin({
"process.env": {
VUE_APP_BASE_URL: JSON.stringify("http://localhost:3000")
}
}),
]
5. 區(qū)分生產(chǎn)環(huán)境和開發(fā)環(huán)境
新建兩個文件
webpack.dev.js 開發(fā)環(huán)境使用
webpack.prod.js 生產(chǎn)環(huán)境使用
webpack.config.js 公用配置
開發(fā)環(huán)境與生產(chǎn)環(huán)境的不同
5.1 開發(fā)環(huán)境不需要壓縮代碼
需要熱更新
css不需要提取到css文件
sourceMap
...
壓縮代碼
不需要熱更新
提取css,壓縮css文件
sourceMap
構(gòu)建前清除上一次構(gòu)建的內(nèi)容
...
安裝所需依賴
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 用于刪除上次構(gòu)建的文件
webpack-merge 合并 webpack配置
copy-webpack-plugin 用戶拷貝靜態(tài)資源
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");,
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");,
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 生產(chǎn)環(huán)境配置
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");
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屬性中新增一個插件
在開發(fā)環(huán)境中,我們是沒必要進(jìn)行模塊打包分析的,所以我們將插件配置在了生產(chǎn)環(huán)境的配置項中
運行打包命令
npm run build
執(zhí)行成功后會自動打開這個頁面
7. 集成 VueRouter,Vuex
首先是安裝相關(guān)依賴
npm install vue-router vuex --save7.1 集成 Vue-Router
新增視圖組件 在 src 目錄下新增兩個視圖組件 src/views/Home.vue 和 src/views/About.vue
// src/views/Home.vue
<template>
<div class="Home">
<h2>Homeh2>
div>
template>
<script>
export default {
name: "Home",
data() {
return {};
}
};
script>
<style lang="scss" scoped>
style>
About.vue 內(nèi)容跟 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"App"> Hello World// router-link 組件 用來導(dǎo)航到哪個路由"/Home">go Home "/About">go About // 用于展示匹配到的路由視圖組件
運行 npm run serve 命令,如沒配置錯誤,是可以看到點擊不同的路由,會切換到不同的路由視圖
7.2 配置路由懶加載在沒配置路由懶加載的情況下,我們的路由組件在打包的時候,都會打包到同一個js文件去,當(dāng)我們的視圖組件越來越多的時候,就會導(dǎo)致這個 js 文件越來越大。然后就會導(dǎo)致請求這個文件的時間變長,最終影響用戶體驗
安裝依賴
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 文件
在 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 文件 導(dǎo)入 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 class="App">
<div>
<router-link to="/Home">go Homerouter-link>
<router-link to="/About">go Aboutrouter-link>
div>
<div>
<p>{{getCounter}}p>
<button @click="add">addbutton>
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
當(dāng)點擊按鈕的時候,可以看到我們的getCounter一直在增加
8 總結(jié)到目前為止,我們已經(jīng)成功的自己搭建了一個 vue 開發(fā)環(huán)境,不過還是有一些功能欠缺的,有興趣的小伙伴可以交流交流。在搭建過程中,還是會踩很多坑的。
如果還不熟悉 webpack 的話,建議自己搭建一次。可以讓自己能深入的理解 vue-cli 替我們做了什么
推薦閱讀
使用 webpack 的各種插件提升你的開發(fā)效率
vue-cli3 項目從搭建優(yōu)化到docker部署
Event Loop 原來是這么回事
通過vue-cli3構(gòu)建一個SSR應(yīng)用程序
歡迎關(guān)注公眾號“碼上開發(fā)”,每天分享最新技術(shù)資訊
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/6752.html
摘要:經(jīng)歷月份開放的簡歷,收到了蠻多詢問和面試,算是招人旺季,需要跳槽的小伙伴抓住機(jī)會。現(xiàn)在是面試了家公司左右,有些高頻問題會標(biāo)記次數(shù)總次數(shù),可供大家參考。最后祝大家面試順利,拿到心儀的,寫錯的地方請不吝賜教,謝謝。 經(jīng)歷 7月份開放的簡歷,收到了蠻多詢問和面試,算是招人旺季,需要跳槽的小伙伴抓住機(jī)會。一開始廣泛看面試題,沒抓住重點復(fù)習(xí),有很多平時也沒怎么用到,導(dǎo)致一開始面試的時候,問的問題...
摘要:經(jīng)歷月份開放的簡歷,收到了蠻多詢問和面試,算是招人旺季,需要跳槽的小伙伴抓住機(jī)會。現(xiàn)在是面試了家公司左右,有些高頻問題會標(biāo)記次數(shù)總次數(shù),可供大家參考。最后祝大家面試順利,拿到心儀的,寫錯的地方請不吝賜教,謝謝。 經(jīng)歷 7月份開放的簡歷,收到了蠻多詢問和面試,算是招人旺季,需要跳槽的小伙伴抓住機(jī)會。一開始廣泛看面試題,沒抓住重點復(fù)習(xí),有很多平時也沒怎么用到,導(dǎo)致一開始面試的時候,問的問題...
摘要:獲取的對象范圍方法獲取的是最終應(yīng)用在元素上的所有屬性對象即使沒有代碼,也會把默認(rèn)的祖宗八代都顯示出來而只能獲取元素屬性中的樣式。因此對于一個光禿禿的元素,方法返回對象中屬性值如果有就是據(jù)我測試不同環(huán)境結(jié)果可能有差異而就是。 花了很長時間整理的前端面試資源,喜歡請大家不要吝嗇star~ 別只收藏,點個贊,點個star再走哈~ 持續(xù)更新中……,可以關(guān)注下github 項目地址 https:...
摘要:五六月份推薦集合查看最新的請點擊集前端最近很火的框架資源定時更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語。葉上初陽乾宿雨,水面清圓,一一風(fēng)荷舉。家住吳門,久作長安旅。五月漁郎相憶否。小楫輕舟,夢入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請::點擊::集web前端最近很火的vue2框架資源;定時更新,歡迎 Star 一下。 蘇...
閱讀 1370·2021-11-22 09:34
閱讀 2581·2021-11-12 10:36
閱讀 1111·2021-11-11 16:55
閱讀 2324·2020-06-22 14:43
閱讀 1457·2019-08-30 15:55
閱讀 1975·2019-08-30 15:53
閱讀 1764·2019-08-30 10:50
閱讀 1217·2019-08-29 12:15