blog

Vueプロジェクトの構築

webpack-chainはチェイニングと呼ばれ、webpackの内部設定をより細かい粒度で制御することができます。 複数の環境で異なる設定を行いたい場合は、vue-cliが提供するモードを利用します...

Feb 25, 2020 · 7 min. read
シェア

コード指定

プロジェクト構成

I.基本構成

const port = 7070;
module.exports = {
 publicPath: '/best-practice', // アプリケーション・パッケージのデプロイメント。 URL 
 devServer: {
 port, 
 }
};

II.webpackの設定: configureWebpack

  1. コンポーネントの保存パスのエイリアスを設定します --- vue.config.js
const path=require('path')
module.exports = {
 configureWebpack: {
 resolve: {
 alias: {
 comps: path.join(__dirname, 'src/components'),
 }
} }
}
  1. webpackの設定項目に⻚タイトルを設定 --- vue.config.js
const path=require('path')
module.exports = {
 configureWebpack: {
 resolve: {
 alias: {
 comps: path.join(__dirname, 'src/components'),
 }
 } 
 }
}
// ホストサーバーでlodashの補間構文を使う。./public/index.html
// <title><%= webpackConfig.name %></title>
  1. 環境に応じた条件設定 --- vue.config.js
// 関数をconfigureWebpack
// 直接修正することも、マージ用の設定オブジェクトを返すこともできる。 
configureWebpack: config => {
 config.resolve.alias.comps = path.join(__dirname, 'src/components')
 if (process.env.NODE_ENV === 'development') {
 config.name = 'vueプロジェクトのベストプラクティス' }
 else {
 config.name = 'Vue Best Practice'
 }
}

III.webpackの設定: chainWebpack

webpack-chain連鎖操作として知られており、webpackの内部設定をより細かく制御することができます。

  1. アイコンをダウンロードして src/icons/svg に保存します。
  2. 依存関係:svg-sprite-loaderのインストール
npm i svg-sprite-loader -D
  1. ルールの修正と新規ルールの追加 - vue.config.js
// resolve絶対パス取得関数を定義する 
const path = require('path')
function resolve(dir) {
 return path.join(__dirname, dir)
}
chainWebpack(config) {
// アイコンディレクトリ内のsvgファイル処理を除外するsvgルールを設定する。
// 目標は、svgルールに除外オプションを追加することである。exclude:['path/to/icon']
config.module.rule("svg")
 .exclude.add(resolve("src/icons"))
// アイコンのルールを追加するsvg-sprite-loaderのアイコンディレクトリを扱う。svg
config.module.rule('icons')
.test(/\.svg$/)
.include.add(resolve('./src/icons')).end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
 .options({symbolId: 'icon-[name]'})
}
  1. ---App.vue
<template>
 <svg>
 <use xlink:href="#icon-wx" />
 </svg>
</template>
<script>
 import '@/icons/svg/wx.svg'
</script>
  1. 自動インポート
//   icons/index.js
const req = require.context('./svg', false, /\.svg$/)
req.keys().map(req);
// SvgIconコンポーネントを作成する。components/SvgIcon.vue
<template>
 <svg :class="svgClass" v-on="$listeners">
 <use :xlink:href="iconName"/>
 </svg>
</template>
<script>
 export default {
 name: 'SvgIcon',
 props: {
 iconClass: {
 type: String,
 required: true
 },
 className: {
 type: String,
 default: ''
 }
 },
 computed: {
 iconName() {
 return `#icon-${this.iconClass}`
 },
 svgClass() {
 if (this.className) {
 return 'svg-icon ' + this.className
 } else {
 return 'svg-icon'
 }
 }
 }
 }
</script>
<style scoped>
 .svg-icon {
 width: 1em;
 height: 1em;
 vertical-align: -0.15em;
 fill: currentColor;
 overflow: hidden;
 }
</style>
// 一番外側の--- main.js
import './icons'

IV.環境変数とモード

複数の環境を異なるように設定したい場合は、vue-cliが提供するモードを利用できます。デフォルトでは、development、production、testの3つのモードがあり、対応する設定ファイルは.env.developmentです。

  1. 開発用の設定項目を定義するには、.env.devを作成します。
# サーバー側でのみ使用できる 
name=' '
# クライアント側で使用できる 
VUE_APP_DONG=candy- 
  1. モード名を上書きするようにmodeオプションを変更します ---package.json
// --modeデフォルトのdevelopment
"serve": "vue-cli-service serve --mode dev" 

パーミッション制御

ルートには2つのタイプがあります: constantRoutesとasyncRoutesです。 前者は直接アクセスできるデフォルトのルートで、後者で定義されたルートはカーネルカラーとフィルタリングを取得するために最初にログインする必要があり、その後動的にルーターに追加されます。

  1. 非同期にルーティングテーブルを取得します。ユーザがログインし、アクセス可能なルーティングテーブルをバックエンドに要求すると、バックエンドは動的にアクセス可能なサーフェスを生成し、バックエンドから返されたルーティングテーブルのコンポーネント名をローカルコンポーネントにマッピングします。
 
// フロントエンドコンポーネント名とコンポーネントマッピング表 const map = {
//xx: require('@/views/xx.vue').default // 同期
 xx: () => import('@/views/xx.vue') // 非同期の方法
 }
// サーバーはasyncRoutes 
const asyncRoutes = [
 { path: '/xx', component: 'xx',... }
]
// asyncRoutesを繰り返し、コンポーネントをmap[component] 
function mapComponent(asyncRoutes) {
 asyncRoutes.forEach(route => {
 route.component = map[route.component];
 if(route.children) {
 route.children.map(child => mapComponent(child))
 }
 }) 
}
mapComponent(asyncRoutes)
import store from "@/store";
const permission = {
 inserted(el, binding) {
 // コマンドの値を取得する:ボタンによって要求されたロールの配列。
 const { value:pRoles } = binding;
 // ユーザーの役割を取得する
 const roles = store.getters && store.getters.roles;
 if (pRoles && pRoles instanceof Array && pRoles.length > 0) { 
 // ユーザーロールがボタンによって要求されたロールを持っているかどうかを判断する。
 const hasPermission = roles.some(role => {
 return pRoles.includes(role);
 });
 // 現在のdom
 if (!hasPermission) {
 el.parentNode && el.parentNode.removeChild(el);
 }
 } else {
 throw new Error(`以下のようなボタン要求ロールの配列を指定する必要がある。v-permission="['admin','editor']"`);
 }
 }
};
export default permission;

main.jsは以下を導入しています。

import vPermission from "./directives/permission";
Vue.directive("permission", vPermission);

App.vue

<button v-permission="['admin', 'editor']">editor button</button>
<button v-permission="['admin']">admin button</button>
  1. v-permissionのボタンパーミッションは操作できないのでv-ifを使用
  2. ナビゲーションメニューは、ルーティング情報に基づいて動的に生成され、パーミッションの判定と組み合わされます。複数レベルのルートの入れ子に対応する必要があるため、再帰的なコンポーネントが使用されます。

ラッピングリクエスト

axiosのパッケージ化、コンフィギュレーションの統一処理、リクエストとレスポンスのインターセプト。

  1. インストール
npm i axios -S
  1. @/utils/request.js
npm i axios -S

使用方法

import Axios from "axios";
import { MessageBox, Message } from "element-ui";
import store from "@/store";
// アクシオスのインスタンスを作成する
const axios = Axios.create({
 baseURL: process.env.VUE_APP_BASE_API, // urlベースアドレス、異なるデータソースのURL変更の問題を解決する。
 // withCredentials: true, // クロスドメインでクッキーを送信したい場合、このオプションを設定する必要がある。
 timeout: 5000 //  
});
// リクエストの傍受
axios.interceptors.request.use(
 config => {
 // do something
 const token = localStorage.getItem('token')
 if (token) {
 // トークン・リクエスト・ヘッダーの設定
 config.headers["Authorization"] = 'Bearer ' + token;
 }
 return config;
 },
 error => {
 // リクエストエラーの処理
 //console.log(error) // for debug
 return Promise.reject(error);
 }
);
// レスポンスの傍受
axios.interceptors.response.use(
 // カスタムコードでレスポンスステータスを決定する、HTTPステータスコードを決定することもできる。
 response => {
 // データのみを返す
 const res = response.data;
 // code1でなければエラーと判定される。
 if (res.code !== 1) {
 Message({
 message: res.message || "Error",
 type: "error",
 duration: 5 * 1000
 });
 //  10008-不正なトークン; 10012-他のクライアントがログインしている; 10014-トークンの有効期限;
 if (res.code === 10008 || res.code === 10012 || res.code === 10014) {
 // 再ログイン
 MessageBox.confirm(
 "ログイン状態が異常なので、もう一度ログインしてほしい",
 "ログイン情報の確認",
 {
 confirmButtonText: "再ログイン",
 cancelButtonText: " ",
 type: "warning"
 }
 ).then(() => {
 store.dispatch("user/resetToken").then(() => {
 location.reload();
 });
 });
 }
 return Promise.reject(new Error(res.message || "Error"));
 } else {
 return res;
 }
 },
 error => {
 //console.log("err" + error); // for debug
 Message({
 message: error.message,
 type: "error",
 duration: 5 * 1000
 });
 return Promise.reject(error);
 }
);
export default axios;
  1. VUE_APP_BASE_API 環境変数を設定し、.env.develop ファイルを作成します。

  2. サービスインタフェースを記述 创建@/api/user.js

クロスドメインの解決

要求されたインタフェースが別のサーバにある場合は、クロスドメインの問題を回避するためにプロキシを設定する必要があります。

プロジェクトのテスト

主にユニットテストの書き方やテストレポートの見方などを紹介します。

Read next