從零開始作Vue前端架構(1)

前言

想一想也已經作過很多架構的項目了,有基於vue,基於react,基於thinkPHP,基於laravel的。css

作多了,也就對現有的架構有各類想法,有好的,有壞的,總之,用起來仍是不爽。vue-cli雖然能夠很快地構建並使用,尤爲是vue-cli v3.0,把webpack都封進@vue/cli的sdk裏了,用起來更加乾淨、簡潔。html

可是,對於愛折騰的咱們,好吧,開個玩笑。重來,可是,對於頁面的優化,還有項目的架構,咱們不得不作多多少少的修改。前端

好了,介紹完畢,接下來,我就從零開始,一步一步建起先後端徹底分離的前端架構了。vue

步驟

因爲要介紹的不少,全寫在一篇裏,有些太長了。node

因此,我會分爲:react

  1. 建立開發環境下的webpack配置文件webpack

  2. 配置eslint、babel、postcsslaravel

  3. 建立項目文件、目錄架構git

  4. 經過koa實現本地數據接口模擬github

  5. 建立發佈環境下的webpack配置文件

  6. 建立測試環境下的webpack配置文件、以及測試用例 (TODO)

  7. 自動初始化構建項目(TODO)

這七篇來分別介紹。

開發

1、初始化項目

  1. 建立項目文件夾 咱們就叫vue-construct

  2. 初始化git git init

  3. 初始化npm npm init

  4. 建立項目文件 爲了能讓webpack跑起來,而不是一口氣只講配置而不運行一下,那樣未免有些空洞,因此咱們先建立一點項目文件和目錄。 在這以前咱們先安裝兩個包:vue、vue-router, npm i -S vue vue-router。 咱們將項目代碼相關文件都放在名爲app的文件夾下。我先都建立完,而後一個個介紹。

├── app
│   ├── app.vue
│   ├── common
│   │   ├── img
│   │   ├── js
│   │   └── scss
│   ├── index.html
│   ├── index.js
│   ├── router
│   │   └── index.js
│   └── views
│       └── home
│           └── index.vue
├── .gitignore
├── package-lock.json
├── package.json
└── webpack.config.js
複製代碼

node_modules的話就忽略了。

文件/文件夾 用途
app.vue 做爲vue的主文件
common 裏面放公共的代碼
index.html 頁面模板文件
index.js 項目主入口文件
router 放vue對應的router文件
views 放視圖文件
.gitignore 忽略node_module

我們暫且不關係這些文件裏的具體代碼是什麼,等webpack配置完再說。

2、配置webpack.config.js

  1. 安裝一系列的包: 爲了webpack的運行,須要安裝
webpack
webpack-dev-server
複製代碼

爲了處理vue單頁文件,安裝:

vue-loader
複製代碼

爲了處理scss文件並從js中抽離,安裝:

node-sass
style-loader
css-loader
sass-loader
vue-style-loader
postcss
postcss-loader
autoprefixer
extract-text-webpack-plugin
複製代碼

爲了處理圖片和字體文件,安裝:

file-loader
url-loader
複製代碼

爲了支持高級語法-babel,安裝:

babel
babel-loader
babel-plugin-syntax-dynamic-import
babel-plugin-transform-object-rest-spread
babel-polyfill
babel-preset-env
複製代碼

爲了驗證代碼格式-eslint,安裝:

eslint
eslint-loader
eslint-plugin-html
babel-eslint
複製代碼
  1. 配置webpack.config.js文件
const webpack = require('webpack')
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
// 爲了抽離出兩份CSS,建立兩份ExtractTextPlugin
// base做爲基礎的css,基本不變,因此,能夠抽離出來充分利用瀏覽器緩存
// app做爲迭代的css,會常常改變
const isProduction = process.env.NODE_ENV === 'production'
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const extractBaseCSS =
  new ExtractTextPlugin(
    {
      filename:'static/css/base.[chunkhash:8].css',
      allChunks: true,
      disable: !isProduction // 開發環境下不抽離css
    }
  )
const extractAppCSS
  = new ExtractTextPlugin(
    {
      filename:'static/css/app.[chunkhash:8].css',
      allChunks: true,
      disable: !isProduction // 開發環境下不抽離css
    }
  )

// 減小路徑書寫
function resolve(dir) {
  return path.join(__dirname, dir)
}

// 網站圖標配置
const favicon = resolve('favicon.ico')

// __dirname: 老是返回被執行的 js 所在文件夾的絕對路徑
// __filename: 老是返回被執行的 js 的絕對路徑
// process.cwd(): 老是返回運行 node 命令時所在的文件夾的絕對路徑
const config = {
  // sourcemap 模式
  devtool: 'cheap-module-eval-source-map',
  // 入口
  entry: {
    app: resolve('app/index.js')
  },
  // 輸出
  output: {
    path: resolve('dev'),
    filename: 'index.bundle.js'
  },
  resolve: {
    // 擴展名,好比import 'app.vue',擴展後只須要寫成import 'app'就能夠了
    extensions: ['.js', '.vue', '.scss', '.css'],
    // 取路徑別名,方便在業務代碼中import
    alias: {
      api: resolve('app/api/'),
      common: resolve('app/common/'),
      views: resolve('app/views/'),
      components: resolve('app/components/'),
      componentsBase: resolve('app/componentsBase/'),
      directives: resolve('app/directives/'),
      filters: resolve('app/filters/'),
      mixins: resolve('app/mixins/')
    }
  },
  // loaders處理
  module: {
    rules: [
      {
        test: /\.js$/,
        include: [resolve('app')],
        loader: [
          'babel-loader',
          'eslint-loader'
        ]
      },
      {
        test: /\.vue$/,
        exclude: /node_modules/,
        loader: 'vue-loader',
        options: {
          extractCSS: true,
          loaders: {
            scss: extractAppCSS.extract({
              fallback: 'vue-style-loader',
              use: [
                {
                  loader: 'css-loader',
                  options: {
                    sourceMap: true
                  }
                },
                {
                  loader: 'postcss-loader',
                  options: {
                    sourceMap: true
                  }
                },
                {
                  loader: 'sass-loader',
                  options: {
                    sourceMap: true
                  }
                }
              ]
            })
          }
        }
      },
      {
        test: /\.(css|scss)$/,
        use: extractBaseCSS.extract({
          fallback: 'style-loader',
          use: [
            {
              loader: 'css-loader',
              options: {
                sourceMap: true
              }
            },
            {
              loader: 'postcss-loader',
              options: {
                sourceMap: true
              }
            },
            {
              loader: 'sass-loader',
              options: {
                sourceMap: true
              }
            }
          ]
        })
      },
      {
        test: /\.(png|jpe?g|gif|svg|ico)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 8192,
          name: isProduction
            ? 'static/img/[name].[hash:8].[ext]'
            : 'static/img/[name].[ext]'
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 8192,
          name: isProduction
            ? 'static/font/[name].[hash:8].[ext]'
            : 'static/font/[name].[ext]'
        }
      }
    ]
  },
  plugins: [
    // html 模板插件
    new HtmlWebpackPlugin({
      favicon,
      filename: 'index.html',
      template: resolve('app/index.html')
    }),
    // 抽離出css
    extractBaseCSS,
    extractAppCSS,
    // 熱替換插件
    new webpack.HotModuleReplacementPlugin(),
    // 更友好地輸出錯誤信息
    new FriendlyErrorsPlugin()
  ],
  devServer: {
    proxy: {
      // 凡是 `/api` 開頭的 http 請求,都會被代理到 localhost:7777 上,由 koa 提供 mock 數據。
      // koa 代碼在 ./mock 目錄中,啓動命令爲 npm run mock。
      '/api': {
        target: 'http://localhost:7777', // 若是說聯調了,將地址換成後端環境的地址就哦了
        secure: false
      }
    },
    host: '0.0.0.0',
    port: '9999',
    disableHostCheck: true, // 爲了手機能夠訪問
    contentBase: resolve('dev'), // 本地服務器所加載的頁面所在的目錄
    // historyApiFallback: true, // 爲了SPA應用服務
    inline: true, //實時刷新
    hot: true  // 使用熱加載插件 HotModuleReplacementPlugin
  }
}

module.exports = {
  config: config,
  extractBaseCSS: extractBaseCSS,
  extractAppCSS: extractAppCSS
}
複製代碼

總結

這一篇主要就作了三件事:

  1. 建立簡單的項目結構
  2. 安裝了這篇,以及以後要用到npm包
  3. 配置開發環境的Webpack

下一篇咱們將配置eslint、babel、postcss - 從零開始作Vue前端架構(2)

項目完整代碼

Vue前端架構-by 子咻

相關文章
相關標籤/搜索