天天看點

從0到1架構webpack+vue前端項目,你自己搭建過vue開發環境嗎

前言:

平時大家開發vue項目的時候,相信大部分人都是使用 vue-cli腳手架生成的項目架構,然後

npm run install

安裝依賴,

npm run serve

啟動項目然後就開始寫業務代碼了。對項目裡的webpack封裝和配置了解的不清楚,容易導緻出問題不知如何解決,或者不會通過webpack去擴充新功能,我們經常會迷惘webpack+vue項目究竟是怎樣搭建起來的呢?文章比較長,需要些耐心,雖然可以直接在GitHub上拉寫好的代碼,但我更希望你能跟着文章一步步進行code。

通過本文你能學習到:

  • node項目初始化
  • webpack安裝及配置
  • ES6代碼轉換成ES5代碼
  • scss/sass/less/stylus轉css
  • .vue檔案轉換成js檔案
  • 使用 jpg、png,font等資源檔案
  • 自動添加css各浏覽器産商的字首
  • webpack搭建本地服務及代碼熱更新
  • vue目錄結構及vue-router使用
  • 資源預加載
  • 自定義環境變量和常量
  • 區分開發環境打包跟生産環境打包

源碼位址

一、初始化項目:

在你想生成檔案的目錄下,打開指令行執行

npm init

然後一路回車就行了,主要是生成一些項目基本資訊。最後會生成一個

package.json

檔案

二、安裝webpack及腳手架

npm install webpack -D
npm install -D webpack-cli
           

三、ES6+轉碼為ES5及适思考配浏覽器:

配置 ES6/7/8 轉 ES5代碼

安裝相關依賴

npm install babel-loader @babel/core @babel/preset-env -D
           

根目錄下建立一個src檔案夾,然後再建一個

main.js

檔案,寫2句代碼

// src/main.js
let i = 4.0;
console.log('hello webpack'+ i);
           

webpack.config.js檔案

在項目根目錄下增加

webpack.config.js

檔案,然後寫入下面這份簡單的配置:

module.exports = {
    mode: 'development',// 指定開發者打包模式
    entry : './src/main.js',//入口檔案
    output : {//輸出檔案
        filename : 'index.js',//輸出檔案名
        path :  __dirname+'/public'//輸出檔案路徑
    },
    module : {
        rules: [
            {/*将js或者jsx檔案轉碼成es5*/
                test: /\.jsx?$/,// 正則惰性比對字尾名為js或者jsx的檔案
                exclude: /node_modules/,//排除這個檔案夾
                use: {
                    loader: 'babel-loader',
                    options: {
                      presets: ['@babel/preset-env']
                    }
                  }
            },
        ]
    },
}
           

然後在package.json的scripts先添加下面這個指令:

"build": "webpack --config ./webpack.config.js",
           

最後運作:

npm run build
           

可以看到根目錄會生成一個

public

檔案夾,而且下面有一個由

src/main.js

打包出來的

index.js

思考:

babel-loader

可以将ES6代碼轉為ES5代碼,進而可以在現有環境執行,是以我們可以用ES6編寫,而不用考慮環境支援的問題;有些浏覽器版本的釋出早于ES6的定稿和釋出,是以如果在程式設計中使用了ES6的新特性,而浏覽器沒有更新版本,或者新版本中沒有對ES6的特性進行相容,那麼浏覽器就會無法識别ES6代碼,例如IE9根本看不懂代碼寫的let和const是什麼東西?隻能選擇報錯,這就是浏覽器對ES6的相容性問題;我們可以通過 babel-polyfill 對一些不支援新文法、相容性差的用戶端提供新文法的實作。

這個思考由你來完成吧,如果你不想加入可以跳過,不影響後面的操作

四、使用 html-webpack-plugin來建立html頁面

1.安裝html-webpack-plugin插件

npm install html-webpack-plugin -D
           

2.添加入口檔案

在根目錄下增加index.html檔案,添加下面代碼:

<!DOCTYPE html>
<html >
<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>hellow diyVue</title>
</head>
<body>
  <div id="app"></div>
<script type="text/javascript" src="index.js"></script></body>
</html>
           

3.修改webpack.config.js配置

const path = require('path');
const HtmlWebpackplugin = require('html-webpack-plugin');
module.exports = {
    mode: 'development',// 指定開發者打包模式
    entry : './src/main.js',//入口檔案
    output : {//輸出檔案
        filename : 'index.js',//輸出檔案名
        path :  __dirname+'/public'//輸出檔案路徑
    },
    module : {
        rules: [
            {/*将js或者jsx檔案轉碼成es5*/
                test: /\.jsx?$/,// 正則惰性比對字尾名為js或者jsx的檔案
                exclude: /node_modules/,//排除這個檔案夾
                use: {
                    loader: 'babel-loader',
                    options: {
                      presets: ['@babel/preset-env']
                    }
                  }
            },
        ]
    },
    plugins:[
        new HtmlWebpackplugin({
            filename: 'index.html', // 打包後的檔案名,預設是index.html
            template: path.resolve(__dirname, 'index.html') // 導入被打包的檔案模闆
        })
    ]
}
           

4.檢視效果

運作

npm run build

,我們可以看到

public

檔案夾下有一個

index.html

生成了,而且還引入了

src/main.js

的壓縮包

index.js

五、安裝配置并使用vue

1.安裝插件及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 程序。

2.修改webpack.config.js配置

const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackplugin = require('html-webpack-plugin');
module.exports = {
    mode: 'development',// 指定開發者打包模式
    entry : './src/main.js',//入口檔案
    output : {//輸出檔案
        filename : 'index.js',//輸出檔案名
        path :  __dirname+'/public'//輸出檔案路徑
    },
    module : {
        rules: [
            {/*将js或者jsx檔案轉碼成es5*/
                test: /\.jsx?$/,// 正則惰性比對字尾名為js或者jsx的檔案
                exclude: /node_modules/,//排除這個檔案夾
                use: {
                    loader: 'babel-loader',
                    options: {
                      presets: ['@babel/preset-env']
                    }
                  }
            },
            {
                test: /\.vue$/,
                use: [
                  {
                    loader: 'cache-loader'
                  },
                  {
                    loader: 'thread-loader'
                  },
                  {
                    loader: 'vue-loader',
                    options: {
                      compilerOptions: {
                        preserveWhitespace: false
                      },
                    }
                  }
                ]
              },
        ]
    },
    plugins:[
        new HtmlWebpackplugin({
            filename: 'index.html', // 打包後的檔案名,預設是index.html
            template: path.resolve(__dirname, 'index.html') // 導入被打包的檔案模闆
        }),
        new VueLoaderPlugin()
    ]
}
           

3.使用vue

在 src 建立一個 App.vue:

<template>
  <div class="App">
    Hello {{msg}}
  </div>
</template>

<script>
export default {
  name: 'App',

  data() {
    return {
        msg: "diyVue",
    };
  }
};
</script>
           

修改src/main.js的代碼:

import Vue from 'vue'
import App from './App.vue'

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

4.打包及運作vue

再次運作

npm run build

,然後在浏覽器打開

public/index.html

,可以發現

vue

已經可以運作了

從0到1架構webpack+vue前端項目,你自己搭建過vue開發環境嗎

六、安裝本地服務及代碼熱更新

1.安裝

webpack-dev-server

npm install webpack-dev-server -D
           

2.修改webpack.config.js配置

// ...
    devServer: { //node本地伺服器
        host: '127.0.0.1',
        port: 8010
    },
// ...
           

3.在package.json的scripts中增加一行啟動本地服務指令:

"dev": "webpack-dev-server --env.dev",
           

4.運作以及檢視效果

  • 運作

    npm run dev

    從0到1架構webpack+vue前端項目,你自己搭建過vue開發環境嗎
  • 浏覽器打開

    http://127.0.0.1:8010/

    從0到1架構webpack+vue前端項目,你自己搭建過vue開發環境嗎
    我們可以發現本地服務已經成功啟動了,而且當我們修改

    src/app.vue

    的代碼後,浏覽器是會自動重新整理的(熱更新)。一個簡單的vue項目我們已經搭建出來了,之後我們可以像堆積木一樣添加自己想要的功能了。

    提醒:

    devServer

    生成的檔案是存在我們電腦的記憶體中的,不在我們的硬碟上(不落盤),可以通過檢視public檔案夾知道,我們改動代碼後這檔案夾下的内容是不會變更的。

七、安裝Vue-Router元件

1.安裝

npm install vue-router --save
           

2.建立相關檔案及編寫代碼

  • 新增視圖元件在 src 目錄下新增兩個視圖元件

    src/view/page1.vue 和 src/view/page2.vue

    page1:
<template>
  <div class="page1">
    <h2>page1</h2>
  </div>
</template>
           

page2:

<template>
  <div class="page2">
    <h2>page2</h2>
  </div>
</template>
           
  • src

    目錄下新增一個

    router/index.js

    檔案
import Vue from 'vue'
import VueRouter from "vue-router";
import page1 from '../view/page1.vue';
import page2 from '../view/page2.vue';
Vue.use(VueRouter)
export default new VueRouter({
  mode: 'hash',
  routes: [
    {
      path: '/page1',
      component: page1
    },
    {
      path: '/page2',
      component: page2
    },
    {
      path: '*',
      redirect: '/page2'
    }
  ]
})
           
  • 修改

    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

元件

<template>
  <div>
    <div class="App">
        Hello {{msg}}
    </div>
    <div>
        <router-link to="/page1">go page1</router-link>
        <router-link to="/page2">go page2</router-link>
        </div>
        <div>
        <router-view></router-view>
        </div>
    </div>
</template>
<script>
export default {
  name: 'App',

  data() {
    return {
        msg: "diyVue",
    };
  }
};
</script>
           

3.運作及測試效果

  • 運作

    npm run dev

  • 測試效果:
    從0到1架構webpack+vue前端項目,你自己搭建過vue開發環境嗎
    到此為止的檔案目錄是這樣的:
    從0到1架構webpack+vue前端項目,你自己搭建過vue開發環境嗎

八、一口氣配置基礎元件

通過前面的學習,相信你已經基本掌握了堆積木的操作,為了節省時間接下我們一次性添加多幾個積木

1.安裝基礎元件

npm install sass-loader dart-sass css-loader style-loader file-loader url-loader postcss-loader autoprefixer -D
           
  • sass-loader, dart-sass

    主要是将

    scss/sass

    文法轉為

    css

  • css-loader

    主要是解析

    css

    檔案
  • style-loader

    主要是将

    css

    解析到

    html

    頁面的

    style

  • postcss-loader autoprefixer

    實作自動添加

    css3

    字首

    2.在webpack.config.js中增加配置

// ...
            {
                test: /\.(scss|sass)$/,
                use: [
                    {
                        loader: 'style-loader'
                    },
                    {
                        loader: 'css-loader'
                    },
                    {
                        loader: 'sass-loader',
                        options: {
                            implementation: require('dart-sass')
                        }
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: [
                                require("autoprefixer") /*自動添加字首*/
                            ]
                        }
                    }
                ]
            },
            {
                test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/,
                use: [{
                  loader: 'url-loader',
                  options: {
                    limit: 10000
                  }
                }]
            }
            // ...
           

3.運作及測試

在src/App.vue後面加入下面樣式代碼:

// ...
<style  scoped>
    .App{
        color:red;
    }
</style>
           

運作後,我們可以看到樣式代碼生效了

從0到1架構webpack+vue前端項目,你自己搭建過vue開發環境嗎

九、自定義環境變量和常量

通過

webpack

提供的

DefinePlugin

插件,可以很友善的定義環境變量

1.我們先建立一個用來以後儲存常量的檔案,在根目錄下添加

config/constant.js

const NODE_ENV = process.env.NODE_ENV; // webpack編譯是擷取node環境的配置資訊
const config = {
     production: { // 生産環境(線上環境)
        DOMAIN: 'production.com', // 上線域名、位址
        FOO_API: 'production.foo.api.com', // api變量
        BAR_API: 'production.bar.api.com', // api變量
        BAZ_API: 'production.baz.api.com', // api變量
     },
     development: { // 開發環境
        DOMAIN: 'development.com', // 測試域名、位址
        FOO_API: 'development.foo.api.com', // api變量
        BAR_API: 'development.bar.api.com', // api變量
        BAZ_API: 'development.baz.api.com', // api變量
     }
}
module.exports = config[NODE_ENV];
           

2.修改webpack.config.js檔案

const webpack = require('webpack');
const constant = require('./config/constant'); // 引入常量檔案
// ...
plugins:[
        // ...
        new webpack.DefinePlugin({ // 定義全局變量
          CONSTANT: JSON.stringify(constant)
        })
    ],
           

3.修改package.json

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

    用來磨平mac和win中的node環境之間的不同,是以我們需要安裝一下
npm install cross-env -D
           
  • NODE_ENV=development

    NODE_ENV=production

    指定node環境

4.運作及調試

  • 由于修改了

    webpack.config.js

    是以需要重新運作

    npm run dev

  • 在src/main.js後面加上一句測試代碼:

    console.log(CONSTANT);

  • 配置成功列印出來
    從0到1架構webpack+vue前端項目,你自己搭建過vue開發環境嗎

十、區分開發環境打包跟生産環境打包

在config下建立兩個檔案

  • webpack.dev.js 開發環境使用
  • webpack.prod.js 生産環境使用
  • webpack.config.js 公用配置

公共配置webpack.config.js

const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackplugin = require('html-webpack-plugin');
const webpack = require('webpack');
const constant = require('./config/constant'); // 引入常量檔案
module.exports = {
    entry : './src/main.js',//入口檔案
    output : {//輸出檔案
        filename : 'index.js',//輸出檔案名
        path :  __dirname+'/public',//輸出檔案路徑
        // publicPath: "public", // 虛拟目錄,自動指向path編譯目錄,放在記憶體中,是以在硬碟上是找不到的 預設是:/
    },
    module : { // 當執行require或import指令時比對下面的加載規則
        rules: [
            {/*将js或者jsx檔案轉碼成es5*/
                test: /\.jsx?$/,// 正則惰性比對字尾名為js或者jsx的檔案
                exclude: /node_modules/,//排除這個檔案夾
                use: {
                    loader: 'babel-loader',
                    options: {
                      presets: ['@babel/preset-env']
                    }
                  }
            },
            { // vue檔案處理
                test: /\.vue$/,
                use: [
                  {
                    loader: 'cache-loader'
                  },
                  {
                    loader: 'thread-loader'
                  },
                  {
                    loader: 'vue-loader',
                    options: {
                      compilerOptions: {
                        preserveWhitespace: false
                      },
                    }
                  },
                ]
            },
            // { // 檔案資源加載 變成base64會跟下面圖檔資源處理沖突是以注釋了
            //     test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/,
            //     use: [{
            //       loader: 'url-loader',
            //       options: {
            //           name: '[name].[ext]'
            //       }
            //     }]
            // },
            { // 圖檔資源處理
                test: /\.(png|jpg|gif|svg)/,
                use: [{
                    loader: "file-loader",
                    options: {
                        name: '[name].[ext]',
                        outputPath: "public/assets/", // 輸出目錄
                        limit: 8192,
                    }
                }]
            }
        ]
    },
    plugins:[
        new HtmlWebpackplugin({
            filename: 'index.html', // 打包後的檔案名,預設是index.html
            template: path.resolve(__dirname, 'index.html') // 導入被打包的檔案模闆
        }),
        new VueLoaderPlugin(),
        new webpack.DefinePlugin({ // 定義全局變量
          CONSTANT: JSON.stringify(constant)
        })
    ],
}
           

開發環境

  • 不需要壓縮代碼
  • 需要本地服務和熱更新
  • css不需要提取到css檔案
  • sourceMap
const merge = require('webpack-merge')
const webpackConfig = require('../webpack.config')
module.exports = merge(webpackConfig, {
  devtool: 'cheap-module-eval-source-map',
  mode: 'development',// 指定開發者打包模式
  devServer: { //node本地伺服器
      host: '127.0.0.1',
      port: 8010
  },
  module : {
      rules: [
        {
          test: /\.(scss|sass)$/,
            use: [
                {
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader'
                },
                {
                    loader: 'sass-loader',
                    options: {
                        implementation: require('dart-sass')
                    }
                },
                {
                    loader: 'postcss-loader',
                    options: {
                        plugins: [
                            require("autoprefixer") /*自動添加字首*/
                        ]
                    }
                }
            ]
        },
      ]
  },
})
           

生産環境

  • 壓縮代碼
  • 不需要本地服務和熱更新
  • 提取css,壓縮css檔案
  • sourceMap
  • 建構前清除上一次建構的内容
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',// 指定開發者打包模式壓縮js代碼
    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',
                options: {
                    plugins: [
                        require("autoprefixer") /*自動添加字首*/
                    ]
                }
              }
            ]
          },
        ]
    },
    plugins: [
        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(), // 用于删除上次建構的檔案
    ]
})
           

安裝所需依賴

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

    使用者拷貝靜态資源

圖檔資源路徑名使用

修改

src/App.vue

<template>
  <div>
    <div class="App">
        <img :src="imgUrl1">
        <div>Hello {{msg}}</div>
    </div>
    <div>
        <router-link to="/page1">go page1</router-link>
        <router-link to="/page2">go page2</router-link>
        </div>
        <div>
        <router-view></router-view>
        </div>
    </div>
</template>
<script>
export default {
  name: 'App',

  data() {
    return {
        msg: "diyVue",
        imgUrl1: require('./assets/logo.png'),
    };
  }
};
</script>
<style  scoped>
    .App{
        color:red;
    }
</style>
           

這次的操作優化了圖檔資源的引用,我們執行

npm run dev

後,在浏覽器打開項目,可以看到

從0到1架構webpack+vue前端項目,你自己搭建過vue開發環境嗎

優化前這個路徑是base64位的,現在變成了一個普通的路徑。

總結:

vue-cli是一個封裝得很完美的vue腳手架,是以它的适應性很強;但是有些大公司他們的前端項目一般不會直接套用這種腳手架,而是需要結合公司内部的元件一步步搭起一個vue前端項目。

單純的vue架構是非常簡單的,但是結合到node環境和webpack一起用的話,有一些不是太熟悉node、webpack的前端同學就會有些蒙圈。這個案例中,我們主要是搭建好了一個webpack環境,然後将需要的東西一件一件組裝起來,雖然不算太完善,但是學會了這種思路的話,我們處理其他前端項目也不難了。

如果幫助到你了,就點贊,哈哈哈,不可能有贊的!