1. 程式人生 > >不使用 vue-cli 與 vue 模版,使用 Vue2.x + webpack4.x 從零開始一步步搭建專案框架

不使用 vue-cli 與 vue 模版,使用 Vue2.x + webpack4.x 從零開始一步步搭建專案框架

說明

這是我根據慕課網上的一個課程 Vue+Webpack打造todo應用 過程一步步搭下來的框架,去掉了業務相關的邏輯。
專案最終的效果包括了引入vue框架;使用CSS前處理器;使用babel;引用圖片等靜態資源;區分開發環境與生成環境,並做相應優化等。基本接近真正做專案時候的配置。
但是!! 畢竟是我個人根據練習課程搭的框架,跟真實工作可能有區別,請謹慎直接用於工作環境!!!

專案的最終成果看這裡:https://gitee.com/Dandelion_/vue-webpack-scaffold
Tips:專案裡面的 commit 對應文章的每一小節,所以大家善用 git checkout <commit>

命令可以很方便地切換到某個 commit 看當前版本的檔案變化哦。當然直接看專案的 commit 列表也行啦。


0. 前言

首先不得不說 vue-cli + vue-webpack 模版真的很方便,vue init webpack my-vue-project 就搭好框架了,而且開發環境生產環境都有了。npm run dev 啟動開發環境,npm run build 釋出生產環境。幾個命令全部搞定了。但是模版有時候可能不夠靈活,或者我們想修改其中一些東西,面對這些需求的時候,理解怎麼搭建起這個 vue + webpack 的環境還是很有用的。那最快捷的方式,當然是自己從頭開始搭一遍啦。心動不如行動,走~~


1. 新建專案

因為不用 vue-cli 和 vue 模版,所以一開始我們就建個空資料夾。

mkdir my-vue-project
cd my-vue-project
npm init # 初始化專案。這時候會問你一些問題,比如專案名稱、作者之類的,照著提示回答問題就好

2. 安裝基本的 npm 包

首先肯定要安裝 vuewebpack。然後 webpack 4.x已經把 cli 單獨拎出來了,所以還要安裝 webpack-cli;然後因為 webpack 本身其實直接能處理的只有 js 資源,是通過各種 loader 讓其他資源可以被 webpack 打包處理的。那麼現在我們要用 vue

寫單檔案元件(就是 .vue 檔案),所以就還要安裝 vue-loader

npm install vue vue-loader webpack webpack-cli --save-dev # --save-dev表示這些只是開發環境所需的依賴

3. 新增專案各種入口檔案

入口檔案都是很普遍的那種,比如根目錄下的 index.htmlsrc 資料夾下的 main.jsapp.vue 等等,我就不一一解釋了。

新增入口檔案後的專案目錄如下:

.
├── dist/
|	├── ...
├── src/
|	├── main.js
|   ├── app.vue
├── node_modules/
|	├── ...
├── index.html
├── package.json

更詳細的專案結構和具體檔案內容可以看 這個commit

4. 新增 webpack 配置檔案

在專案根目錄下新增 webpack.config.js 檔案。內容如下:

const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
    entry: path.join(__dirname, 'src/main.js'), // 專案總入口js檔案
    // 輸出檔案
    output: {
        path: path.join(__dirname, 'dist'), // 所有的檔案都輸出到dist/目錄下
        filename: 'bundle.js'
    },
    module: {
        rules: [{
                // 使用vue-loader解析.vue檔案
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.css$/,
                // 要加上style-loader才能正確解析.vue檔案裡的<style>標籤內容
                use: ['style-loader', 'css-loader']
            }
        ]
    },
    plugins: [
        new VueLoaderPlugin() // 最新版的vue-loader需要配置外掛
    ]
};

5. 新增構建指令碼

package.json 檔案的 scripts 屬性裡新增 build 指令碼

   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1",
+    "build": "webpack --config webpack.config.js"
   },

因為我們添加了一些引用,比如 style-loadercss-loader 等,所以也要安裝相應的包。

npm i style-loader css-loader vue-template-compiler --save-dev

安裝好依賴後執行 npm run build 來構建專案。
構建成功後在專案根目錄啟動一個靜態資源伺服器,然後瀏覽就可以看到以下頁面了。
在這裡插入圖片描述

6. 新增圖片、CSS 前處理器等 loader

圖片 loader 用的是 url-loader,它依賴於 file-loader,比 file-loader 多了一個可以比小於一定大小的圖片直接轉化成 base64 的形式插入到 html 頁面,可以減少網路請求。

CSS 前處理器 我選的是 SASS

安裝依賴:

npm i file-loader url-loader node-sass sass-loader --save-dev

修改 webpack.config.js

		module.exports = 
			{
                 test: /\.css$/,
                 // 要加上style-loader才能正確解析.vue檔案裡的<style>標籤內容
                 use: ['style-loader', 'css-loader']
+            },
+            {
+                test: /\.scss$/,
+                use: [
+                    // 處理順序是從sass-loader到style-loader
+                    'style-loader',
+                    'css-loader',
+                    'sass-loader'
+                ]
+            },
+            {
+                test: /\.(gif|jpg|jpeg|png|svg)$/i,
+                use: [{
+                    loader: 'url-loader',
+                    options: {
+                        // 當檔案大小小於limit byte時會把圖片轉換為base64編碼的dataurl,否則返回普通的圖片
+                        limit: 8192,
+                        name: 'dist/assest/images/[name]-[hash:5].[ext]' // 圖片檔名稱加上內容雜湊
+                    }
+                }]
             }
         ]
     },
     ...

測試一下:

新增 src/assets/styles/global.scss 檔案

+.play {
+    background-image: url('../images/play.png');
+    background-repeat: no-repeat;
+    width: 64px;
+    height: 64px;
+    padding: 0;
+    border: 0;
+    background-color: transparent;
+    margin: 0;
+    cursor: pointer;
+}

src/main.js 引用 global.scss

 import Vue from 'vue'; // 從node_modules引入vue類庫
 import App from './app.vue'; // ES6 語法,相當於 import { default as App } from './app.vue'。因為app.vue用過的是export default {...},所以可以這樣寫
  
+import './assets/styles/global.scss';
+
 new Vue({
     el: '#app',
     components: {

執行 npm run build,重新整理頁面,能看到如下效果:
在這裡插入圖片描述
button 的背景圖是 1.97kb,小於 8192byte,可以看到圖片已經被轉換成 base64 的內容了。

7. 新增 postcss-loader + autoprefixer,自動新增 css 瀏覽器字首

安裝依賴:

npm i postcss-loader autoprefixer --save-dev

新增 postcss 配置檔案 postcss.config.js

const autoprefixer = require('autoprefixer');

module.exports = {
    plugins: [
        autoprefixer({
            browsers: ['last 5 versions']
        })
    ]
};

修改 webpack.config.js

	...
	module: {
        rules: [
			...
			{
                test: /\.css$/,
                use: [
                    // 要加上style-loader才能正確解析.vue檔案裡的<style>標籤內容
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            importLoaders: 1
                        }
                    },
                    'postcss-loader'
                ]
            },
            {
                test: /\.scss$/,
                use: [
                    // 處理順序是從sass-loader到style-loader
                    'style-loader',
                    'css-loader',
                    {
                        loader: 'postcss-loader',
                        options: {
                            sourceMap: true
                        }
                    },
                    'sass-loader'
                ]
            },
            ...

測試一下:

修改 index.html

     <h1>一個用 vue + webpack 搭建的腳手架框架</h1>
     <div id="app"></div>
     <button class="play"></button>
+    <div class="flex">
+        <div class="flex-item"></div>
+        <div class="flex-item"></div>
+        <div class="flex-item"></div>
+    </div>
     <script src="/dist/bundle.js"></script>
 </body>

修改 global.scss


+.flex {
+    display: flex;
+    border: solid #000 2px;
+    width: 300px;
+    height: 100px;
+    .flex-item {
+        flex: 1;
+        background-color: #1296db;
+        border: solid #fff 1px;
+    }
 }

執行 npm run build,重新整理頁面,能看到如下效果:
在這裡插入圖片描述
可以看到 flex 已經加上了瀏覽器字首了。

8. 新增 babel-loader,轉譯 es6 程式碼為 es5 程式碼

新增.babelrc檔案

{
    "presets": [
        "env"
    ],
    "plugins": [
        "transform-vue-jsx"
    ]
}

安裝依賴

npm i [email protected] babel-core babel-preset-env --save-dev

修改 webpack.config.jsmodule.rules 再加一條:

{
    test: /\.js$/,
    exclude: /(node_modules|bower_components)/, // 不處理這兩個資料夾裡的內容
    loader: 'babel-loader'
}

測試一下:

修改 main.js,加上以下程式碼

// 測試babel-loader
class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    sayHello() {
        console.log(`Hello, my name is ${this.name}`);
    }
}

在瀏覽器檢視輸出,如下圖:
在這裡插入圖片描述

如果註釋掉 webpack.config.jsbabel-loader 這條規則,則編譯之後如下:
在這裡插入圖片描述
可以看到 babel-loader 已經起作用了。

9. 新增 html-webpack-plugin,自動生成 index.html 的內容

新增 HtmlWebpackPlugin,在 dist 資料夾也生成 index.html 頁面,而且會自動加上對專案入口 js 檔案的引用,也就是說我們自己寫的 index.html 可以不用再手動指定 js 檔案了,它會把 webpack 配置裡的 entry 當中指定的 js 都插入到生成的 index.html 中,而且當輸出的檔案新增上 hash 值時也可以自動跟蹤。

安裝依賴

npm i html-webpack-plugin --save-dev

修改 webpack.config.js

 const path = require('path');
 const VueLoaderPlugin = require('vue-loader/lib/plugin');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
  
 module.exports = {
     entry: path.join(__dirname, 'src/main.js'), // 專案總入口js檔案
     // 輸出檔案
     output: {
         path: path.join(__dirname, 'dist'),
-        filename: 'bundle.js'
+        filename: 'bundle-[hash].js' // 輸出檔案的名稱加上hash值
     },
     module: {
         rules: [{
             ...
         ]
     },
     plugins: [
-        new VueLoaderPlugin() // 最新版的vue-loader需要配置外掛
+        new VueLoaderPlugin(), // 最新版的vue-loader需要配置外掛
+        new HtmlWebpackPlugin({
+            filename: 'index.html', // 生成的檔名稱
+            template: 'index.html', // 指定用index.html做模版
+            inject: 'body' // 指定插入的<script>標籤在body底部
+        })
     ]
 };

修改 index.html,把原來引用 bundle.js<script> 去掉。

然後我們 build 一下,看 dist 資料夾的輸出。
在這裡插入圖片描述
可以看到 dist 資料夾下多了 index.html 檔案,而且檔案內容自動加上了編譯出來的 bundle.js 檔案的引用。

10. 新增 clean-webpack-plugin,每次 build 之前可以自動先清除輸出資料夾

如果我們對輸出的檔名稱加上了雜湊值的話,每次修改之後的雜湊值都不一樣,就是每次都生成了一個新的檔案,那舊的那些其實就是多餘的檔案了(上面那張圖的 dist 資料夾可以看出來)。因此我們可以用 clean-webpack-plugin 這個外掛,在每次 build 之前先清除輸出資料夾。

安裝依賴

npm i clean-webpack-plugin --save-dev

修改 webpack.config.jsplugins 陣列新增一項

 const path = require('path');
 const VueLoaderPlugin = require('vue-loader/lib/plugin');
 const HtmlWebpackPlugin = require('html-webpack-plugin');
+const CleanWebpackPlugin = require('clean-webpack-plugin');
  
 module.exports = {
     ...
     plugins: [
        new VueLoaderPlugin(), // 最新版的vue-loader需要配置外掛
        new HtmlWebpackPlugin({
            filename: 'index.html', // 生成的檔名稱
            template: 'index.html', // 指定用index.html做模版
            inject: 'body' // 指定插入的<script>標籤在body底部
        }),
+        new CleanWebpackPlugin(['dist'])
    ]
 };

11. 新增 webpack-dev-server,配置更友好的開發環境

webpack-dev-server 可以在本地啟動一個伺服器,而且當有任何檔案修改的時候會自動重新打包,並且重新整理瀏覽器頁面。此外 devServer 還有很多其他配置項,讓我們可以更方便的開發。

安裝依賴

npm i webpack-dev-server cross-env --save-dev

用上 cross-env 是因為我們接下來要修改 package.json 裡的 scripts,而不同的平臺寫scripts 的方式不一樣。

修改 package.json 裡的 scripts

    ...
     "scripts": {
         "test": "echo \"Error: no test specified\" && exit 1",
-        "build": "webpack --config webpack.config.js"
+        "build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
+        "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"
     },
   ....

修改 webpack.config.js,這次改得比較多,可以看這裡的 commit detail

配置好以後我們可以執行 npm run dev 命令啟動一個伺服器了

12. 配置生產環境 css 單獨分離打包,方便瀏覽器快取

安裝依賴

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

修改 webpack.config.js,改動的地方看這個 commit detail

13. 單獨打包類庫檔案

因為類庫檔案是不用像業務程式碼一樣經常更新的,單獨打包可以讓它們在瀏覽器裡快取,提高載入速度。

修改 webpack.config.js,改動的地方看這個 commit detail


到這裡基本的配置都完成了,一個基礎的 vue 專案框架就搭好啦,接下來我們只需要專注於新增自己專案的業務邏輯頁面和程式碼就好了。愉快地敲(xie)代(bug)碼去吧~~

PS: 這個是目前為止用到的配置,其實真實生成環境要做的優化應該還有不少,比如圖片壓縮處理等等,大家要根據自己的專案需要來擴充套件哦。如果以後有用到其他的外掛比較通用的應該會更新這篇文章。嗯,也就是不定期無規律看心情更新2333【逃。。】


本文首發於我的個人網站【https://dandelion-drq.github.io】,歡迎訪問。