前言
想想也已經做過不少架構的專案了,有基於vue,基於react,基於thinkPHP,基於laravel的。
做多了,也就對現有的架構有各種想法,有好的,有壞的,總之,用起來還是不爽。vue-cli雖然可以很快地構建並使用,尤其是vue-cli v3.0,把webpack都封進@vue/cli
的sdk裡了,用起來更加乾淨、簡潔。
但是,對於愛折騰的我們,好吧,開個玩笑。重來,但是,對於頁面的優化,還有專案的架構,我們不得不做多多少少的修改。
好了,介紹完畢,接下來,我就從零開始,一步一步建起前後端完全分離的前端架構了。
步驟
由於要介紹的很多,全寫在一篇裡,有些太長了。
所以,我會分為:
-
建立開發環境下的webpack配置檔案
-
配置eslint、babel、postcss
-
建立專案檔案、目錄架構
-
通過koa實現本地資料介面模擬
-
建立釋出環境下的webpack配置檔案
-
建立測試環境下的webpack配置檔案、以及測試用例 (TODO)
-
自動初始化構建專案(TODO)
這七篇來分別介紹。
開發
一、初始化專案
-
建立專案資料夾 我們就叫
vue-construct
吧 -
初始化git
git init
-
初始化npm
npm init
-
建立專案檔案 為了能讓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配置完再說。
二、配置webpack.config.js
- 安裝一系列的包: 為了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
複製程式碼
- 配置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
}
複製程式碼
總結
這一篇主要就做了三件事:
- 建立簡單的專案結構
- 安裝了這篇,以及之後要用到npm包
- 配置開發環境的Webpack
下一篇我們將配置eslint、babel、postcss - 從零開始做Vue前端架構(2)