1. 程式人生 > >webpack搭建vue專案開發環境【文件向學習】

webpack搭建vue專案開發環境【文件向學習】

為何有這篇文章

各個社群已經有無數篇帖子介紹如何使用webpack搭建前端專案,但無論是出於學習webpack的目的還是為了解決工作實際需要都面臨著一個現實問題,那就是版本更新。別人的帖子可能剛寫好版本就更新了,又要對著帖子找文件。

但這個過程十分重要,因為你想要的一切早已都在文件中給出了說明,在查閱文件的過程中不但能學會正確的使用工具更增強了閱讀文件這種姿勢正確的學習能力。

本文就是記錄一次不斷遭遇版本問題,一路查閱文件達到學習目的的經歷,分享給大家。文章中每個章節提到的相關文件都會在本章節總結,在文章最後我還會將所有相關文件的連結進行彙總出來方便大家學習。

0. 安裝webpack

第一個要查閱的就是webpack的官方文件,由於webpack近年來的使用廣泛,中文文件早已跟上。

webpack官方文件: https://webpack.docschina.org/

我們可以在文件-指南中找到安裝相關的內容。

webpack安裝: https://webpack.docschina.org...

官方已說明不推薦全域性安裝webpack因為這樣會將你專案中的webpack鎖定到指定版本。不需要全域性安裝的可跳過此步驟

全域性安裝webpack:

npm i -g webpack
```

1. 專案初始化

初始化專案

在專案目錄下初始化專案會得到package.json檔案:

npm init
```

安裝webpack和webpack-dev-server以及Vue

webpack4會依賴webpack-cli,如果你沒有安裝也不必擔心,npm會直接報錯提示你

webpack安裝: https://webpack.docschina.org...
webpack-dev-server: https://webpack.docschina.org...
npm i webpack webpack-dev-server webpack-cli --save-dev
npm i vue --save
```

配置webpack.config.js

根目錄下新建webpack的配置檔案webpack.config.js。
配置 入口、出口路徑、打包後文件名和devServer的相關配置項

使用一個webpack的配置檔案: https://webpack.docschina.org...

var path = require('path');
var webpack = require('webpack');

module.exports = {
  //專案入口檔案
  entry: './src/main.js',
  output: {
    //打包出口路徑
    path: path.resolve(__dirname, './dist'),
    //通過devServer訪問路徑
    publicPath: '/dist/',
    //打包後的檔名
    filename: 'main.js'
  },
  mode:'development',
  devServer: {
    historyApiFallback: true,
    overlay: true
  }
};

根目錄下新建index.html(模板如下)

新建index.html作為專案的主體頁面,留出入口檔案,入口檔案的路徑為webpack打包後輸出的路徑。

```<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>webpack-vue</title> <meta name="description" content=""> <meta name="keywords" content=""> </head> <body> <script src="/dist/main.js"></script> </body> </html>

<h3>新建入口檔案</h3>
<p>新建在src目錄用來存放各種元件和靜態檔案,在src目錄下新建入口檔案main.js</p>
<h2>2. webpack的準備工作</h2>
<p>為方便開發除錯,打包以及後期的程式碼編寫便捷,我們需要對webpack進行初步配置</p>
<h3>自定義npm命令</h3>
<p>package.json 增加 scripts:</p>

“scripts”: {
“dev”: “webpack-dev-server --hot --open”,
“build”: “webpack --mode production --progress --hide-modules”
},


<p>這一步的目的是簡化在命令列中輸入複雜指令的操作,如需執行上述兩命令只需要在命令列執行:</p>
<pre><code class="coffeescript">npm run dev
npm run build

webpack-dev-server --hot --open目的是開啟一個本地服務,--hot為熱載入,可實視檢視頁面狀態,--open直接從瀏覽器開啟
webpack --mode production --progress --hide-modules是打包整個專案的指令,--mode production是以生產模式打包,這樣會得到體積更小的檔案,有興趣的同學可以試試不加這個指令,看看差距到底有多大。--progress打印出編譯進度的百分比值,hide-modules隱藏關於模組的資訊
webpack的所有命令列可以在 api-命令列介面(cli) 中找到

webpack命令列介面: https://webpack.docschina.org...

配置webpack解析(resolve)

webpack.config.js中增加:



resolve: {
  //路徑別名
  alias: {
    'vue$': 'vue/dist/vue.esm.js',
    '@':path.resolve(__dirname, './src'),
  },
  //路徑別名自動解析確定的擴充套件
  tensions: ['.js', '.vue', '.json']
},

resolve是webpack關於解析的配置項,alias允許你在專案中使用路徑別名代替複雜的路徑。
extensions會讓webpack自動查詢特定字尾的檔案,在專案中引入檔案時將不必再書寫檔案字尾。
至於為何將vue的路徑別名指向vue/dist/vue.esm.js請看下一章節vue的內容。

webpack解析(resolve): https://webpack.docschina.org...

3. 引入Vue

這一步我們先暫不考慮使用Vue的單頁面元件。

通過檢視 node_modules/vue/dist/README.md 我們可以得到關於webpack配置的說明,引入vue實際上是引用 node_modules/vue/dist/vue.esm.js,有理有據安心使用,並且會告訴你如果你在使用webpack 1.0應該引用vue.common.js,這便是上一步配置路徑別名的依據。

在index.html中添加掛載點dom(#app)

```<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>webpack-vue</title> <meta name="description" content=""> <meta name="keywords" content=""> </head> <body> <div id="app">{{message}}</div> <script src="/dist/main.js"></script> </body> </html>

<h3>在main.js中引入vue</h3>

import Vue from ‘vue’

var app = new Vue({
el: “#app”,
data: {
message: ‘hello webpack!!’
}
})


<p>啟動server,可以預覽到頁面顯示 'hello webpack!!'。</p>
<pre><code class="coffeescript">npm run dev

4. 配置loader——使用 css/scss

webpack預設只能解析js檔案,因此需要在webpack.config.js中配置相應的解析器。

安裝scss和相應樣式檔案解析器

npm i node-sass css-loader vue-style-loader sass-loader –save-dev
```

關於webpack解析樣式的文件比較散亂,通過粗略查閱,
css-loader用來解析css檔案,
style-loader用來解析dom中通過<style></style>注入的樣式,
vue-style-loader是vue官方基於style-loader開發的適用於vue的樣式解析,
sass-loader用來解析sass/scss檔案

webpack - loader: https://webpack.docschina.org...
vue-style-loader: https://www.npmjs.com/package...

在webpack.config.js中配置解析器


  module: {
    rules: [{
      test: /\.css$/,
      use: [
        'vue-style-loader',
        'css-loader'
      ]
    },{
        test: /\.scss$/,
        use: [
          'vue-style-loader',
          'css-loader',
          'sass-loader'
        ]
    },
    {
        test: /\.sass$/,
        use: [
          'vue-style-loader',
          'css-loader',
          'sass-loader?indentedSyntax'
        ]
    }]
  },

以上配置意為:
.css為字尾的檔案使用css-loader, vue-style-loader解析
.scss.sass為字尾的檔案使用sass-loadercss-loader, vue-style-loader解析
解析順序是由下到上的

webpack - module: https://webpack.docschina.org...
webpack - sass-loader: https://webpack.docschina.org...

在專案中使用、引入樣式(測試)

在src目錄下新建目錄assets/styles存放統一樣式,新建index.scss,寫一段scss程式碼:

$appColor:red;
#app{
  color:$appColor;
}

<p>在main.js中引入樣式:</p>

import ‘./assets/styles/index.scss’


<p>再次重啟服務可以看到樣式已經載入成功了</p>
<h2>5. 配置loader——使用圖片</h2>
<p>同樣webpack人無法解析圖片格式的檔案,需要把圖片當做模組使用file-loader解析。</p>
<blockquote>file-loader:<a href="https://webpack.docschina.org/loaders/file-loader/" rel="nofollow noreferrer">https://webpack.docschina.org...</a>
</blockquote>
<h3>安裝file-loader</h3>
<pre><code class="coffeescript">npm i file-loader --save-dev

在webpack.config.js中配置解析器


{
  test: /\.(png|jpg|gif|svg)$/,
  loader: 'file-loader',
  options: {
    name: '[name].[ext]?[hash]'
  }
}

在專案中引入圖片(測試)

在src目錄下按照程式碼中路徑準備一張圖片


Vue.component('myComponent', {
  template: '&lt;img :src="url" /&gt;',
  data() {
    return {
      url: require('./assets/images/logo.png')
    }
  }
})

在index.html中使用該元件

```<div id="app"> {{message}} <my-component></my-component> </div>

<p>重啟服務,圖片應該被成功載入了。</p>
<h2>6. 配置loader——使用babel</h2>
<p>babel可以讓我們在專案中自由的使用es6語法,他會為我們將es6語法編譯成瀏覽器普遍通用的es5語法。<br>在此之前我們必須要對babel有一定的瞭解:</p>
<blockquote>babel官方文件:<a href="https://babel.docschina.org/docs/en/usage" rel="nofollow noreferrer">https://babel.docschina.org/d...</a>
</blockquote>
<p>在babel的使用指南中我們看到安裝babel需要安裝的依賴和配置babel的方法。<br>並且我們得知一個噩耗,babel從7.0開始與之前版本有寫不相容了。如果你的package.json中babel的版本混亂,很容易造成配置失敗。</p>
<h3>安裝babel</h3>
<pre><code class="coffeescript">npm install --save-dev @babel/core @babel/cli @babel/preset-env
npm install --save @babel/polyfill

注意:

  • 其中preset是babel的配置,babel-loader在webpack中解析babel中會用到,polyfill也是babel的一個依賴
  • babel的6.0 和7.0不相容,如果package.json中版本混亂建議降級活升級以統一版本

在webpack.config.js中配置解析器

babel的webpack配置: https://babel.docschina.org/s... 選擇webpack

module增加一條rules:


{
  test: /\.js$/, exclude: /node_modules/,
  loader: "babel-loader"
}

入口檔案更改為:


entry: ["@babel/polyfill", './src/main.js'],

新建配置檔案.babelrc

注意檢視關於env的配置文件,新版本寫法有變化。

@babel/preset-env: https://babel.docschina.org/d...

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "entry"
      }
    ]
  ]
}

檢測es6語法(正常執行說明babel配置成功)

在src下新建util.js


export default function getData() {
    return new Promise((resolve, reject) =&gt; {
        resolve('ok');
    })
}

main.js


//引入元件
import getData from './util';

var app = new Vue({
  el: "#app",
  data: {
    message: 'hello webpack!!'
  },
  methods: {
    async fetchData() {
      const data = await getData();
      this.message = data;
    }
  },
  created() {
    this.fetchData();
  }
})

import getData from './util';

常見報錯

  1. Can't resolve 'babel-polyfill' in 'E:\vue\webpack-vue'
    webpack的入口檔案polyfill版本與配置寫法不匹配
    錯誤:entry: ["babel-polyfill", './src/main.js'],
    正確:entry: ["@babel/polyfill", './src/main.js'],
  2. regeneratorRuntime is not defined
    未安裝@babel/polyfill
    npm i babel-polyfill –save
  3. Plugin/Preset files are not allowed to export objects
    webpack的報錯,版本混亂,不相容
    清理package.json中的babel依賴,刪除node_module,重新執行npm install,再次安裝babel依賴時注意版本統一

7. 使用Vue單檔案元件

vue-loader中介紹瞭如何使用Vue單檔案元件:

vue-loader: https://vue-loader.vuejs.org/zh/

安裝vue-loader及依賴

npm i vue-loader vue-template-compiler –save-dev
```

配置webpack.config.js

Vue單檔案元件: https://vue-loader.vuejs.org/...

// webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  module: {
    rules: [
      // ... 其它規則
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      }
    ]
  },
  plugins: [
    // 請確保引入這個外掛!
    new VueLoaderPlugin()
  ]
}

準備單檔案元件

在src目錄下建立檔案App.vue
在src目錄下新建目錄components用來存放單檔案元件,新建檔案header.vue

App.vue

```<template> <div> <home-header user="vict"></home-header> </div> </template>

<script>
import homeHeader from ‘@/components/header.vue’
export default {
name:‘app’,
components:{
homeHeader
}
}
</script>

<style lang=“scss” scoped>
KaTeX parse error: Expected '}', got 'EOF' at end of input: ….sg{ color:txtColor
}
</style>


<p><strong>header.vue(子元件)</strong></p>

<template>
<div>
header
<span>color</span>
<img src="@/assets/images/logo.png">
{{this.message}} - {{this.user}}
</div>
</template>

<script>
export default {
name:‘homeHeader’,
data () {
return {
message:‘hello world’
}
},
props: {
user:String
}
}
</script>

<style lang=“scss” scoped>
span{
color:green
}
</style>


<p><strong>main.js</strong></p>

import Vue from ‘vue’
import App from ‘./App.vue’
import ‘./assets/styles/index.scss’

new Vue({
render:h => h(App)
}).$mount(’#app’)


<h2>8. 解決靜態檔案</h2>
<p>在.vue中url路徑將被解析成webpack模組請求,<br>這裡建議在webpack.config.js中配置路徑別名以方便在單檔案元件中引用圖片等靜態資源<br>在單檔案元件中可以這樣使用:</p>
```&lt;img src="@/assets/images/logo.png"&gt;

9. 注入Vue Router

vue-router: https://router.vuejs.org/zh/

安裝VueRouter

npm i vue-router –save
```

在main.js的Vue例項中注入Router


import Vue from 'vue'
import App from './App'
//引入router元件
import router from './router/router'
import './assets/styles/reset.css'

new Vue({
  //注入router
  router,
  render:h =&gt; h(App)
}).$mount('#app')

構建router元件

按照路徑建立router檔案:src/router/router.js

router.js


import Vue from 'vue'
import VueRouter from 'vue-router'

import Page1 from '@/components/page1'
import Page2 from '@/components/page2'

Vue.use(VueRouter)
export default new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes: [{
    path: '/',
    name:'home',
    component: Page1
  },{
    path: '/page2',
    name:'page2',
    component: Page2
  }]
})

常見的渲染失敗的原因:

  • router例項的路由配置項 routes,不要誤寫成 routers
  • routes配置項中必須要有路徑為’/’,否則渲染失敗

使用router

在App.vue中可以直接使用<router-view><router-link>標籤

10. 注入Vuex

vuex: https://vuex.vuejs.org/zh/guide/

安裝vuex

npm i vuex –save
```

在main.js的Vue例項中注入store


import Vue from 'vue'
import App from './App'
import router from './router/router'
import store from './store/store'
import './assets/styles/reset.css'

new Vue({
  router,
  store,
  render:h =&gt; h(App)
}).$mount('#app')

構建store目錄

src/store/store.js
可按需要將state、actions、mutations拆分出來

store.js


import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    cur:'OFF',
  },
  actions: {
    changeCur (ctx,cur) {
      ctx.commit('changeCueMutations',cur)
    }
  },
  mutations: {
    changeCueMutations (state,cur) {
      cur == 'OFF' ? state.cur = 'ON' :state.cur = 'OFF'
    }
  }
})

11. 打包釋出

webpack.config.js中如果配置項:mode:'development', build的結果是未經過壓縮的非常的大
修改 package.json 中的scripts,將打包時的mode切換成production


  "scripts": {
    "test": "echo \"Error: no test specified\" &amp;&amp; exit 1",
    "dev": "webpack-dev-server --hot --open",
    "build": "webpack --mode production --progress --hide-modules"
  },

文件彙總

webpack相關

webpack官方文件: https://webpack.docschina.org/
webpack安裝: https://webpack.docschina.org...
webpack-dev-server: https://webpack.docschina.org...
webpack配置: https://webpack.docschina.org...
webpack命令列介面: https://webpack.docschina.org...
webpack解析(resolve): https://webpack.docschina.org...
webpack - loader: https://webpack.docschina.org...
webpack - module: https://webpack.docschina.org...

Vue相關

Vue官方文件(中文): https://cn.vuejs.org/
Vue-cli: https://cli.vuejs.org/zh/guide/
Vue-router: https://router.vuejs.org/
Vuex: https://vuex.vuejs.org/
Vue-loader(單檔案元件): https://vue-loader.vuejs.org/

babel相關

babel官方文件: https://babel.docschina.org/
babel使用指南: https://babel.docschina.org/d...
babel的配置: https://babel.docschina.org/s...
babel-env: https://babel.docschina.org/d...

其他

npm官方: https://www.npmjs.com/
npm CLI(命令列指令): https://docs.npmjs.com/
vue-style-loader: https://www.npmjs.com/package...
node-sass: https://www.npmjs.com/search?...