每天學習一點點 編程PDF電子書、視頻教程免費下載:
http://www.shitanlife.com/code
如何從零開始一個vue+webpack前端工程工作流的搭建,首先我們先從項目的目錄結構入手。一個持續可發展,不斷加入新功能,方便后期維護的目錄結構究竟是長什么樣子的?接下來閏土大叔帶你們一起手摸手學起來。
初級前端初始化目錄篇
項目伊始,我們肯定是先在terminal終端命令行(以下簡稱terminal)cd進入<project name>根目錄,然后輸入 npm init
初始化一個npm項目,在項目根目錄下面就會出現一個package.json文件。 然后就可以安裝依賴了,直接在terminal里輸入 npm i webpack vue vue-loader -D
。當我們把這幾個安裝好以后,terminal這邊會提示我們WARN(警告⚠️):

翻譯過來大意是,vue-loader需要一個css-loader和vue-template-compiler作為它的第三方依賴,所以聽它的話,我們去進行一下安裝:
npm i css-loader vue-template-compiler -D
那下面的警告信息提示我們缺少一些信息,這個其實無關痛癢,所以不需要去關心它。
通過以上簡單幾個步驟,我們的項目就初始化好了。然后在根目錄下面創建一個src文件夾,這是我們源碼放置的目錄。然后我們在src目錄下面新建一個app.vue文件,里面就可以寫一些關於項目的業務代碼:
<template>
<div id="test">{{text}}</div> </template> <script> export default { data () { text: '閏土大叔' } } </script> <style> #test{ font-size:12px; color:green; } </style>
當然這個后綴為.vue 文件是不可以在瀏覽器里直接運行的,我們需要想辦法讓它運行起來。
現在我們要在項目根目錄下新建一個webpack.config.js文件,webpack是幫我們前端來打包資源的,前端資源有很多不同的類型,比如說JavaScript,css,html,image,iconfont等這些資源都是需要通過http請求加載的東西。webpack是將一個js文件加載到瀏覽器端之后,然后去把所有的內容去渲染出來。所以,很多時候,我們可以把js文件作為項目的入口文件。
這個時候,我們在src目錄下新建一個index.js作為入口文件,順便在里面寫點東西:
import Vue from 'vue' import App from './app.vue' const root = document.createElement('div') document.body.appendChild(root) new Vue({ render: (h) => h(App) }).$mount(root)
index.js准備完畢之后,那么在webpack.config.js里面就可以這樣寫:
const path = require('path') module.exports = { entry: path.join(__dirname, 'src/index.js'), output: { filename: 'bundle.js', path: path.join(__dirname, 'dist') } }
在上面的代碼中,__dirname就代表這個文件所在的目錄地址,path.join()的意思就是和后面的字符串路徑拼接起來,形成一個絕對的路徑。
然后通過webpack把所有的文件打包成一個bundle.js文件,並且是能在瀏覽器里面直接運行的代碼。現在我們可以在package.json 文件里的scripts對象里面添加一個腳本:
"scripts": { "build": "webpack --config webpack.config.js" }
看到這兒,肯定有童鞋要問了,為什么要在這里面調用webpack而不是在terminal里面直接運行呢?
因為只有在這里調用webpack,它才會優先調用我們項目里面安裝的webpack版本,如果我們在命令行里面輸入webpack,它會調動全局的webpack,這個時候全局的webpack可能會跟我們項目中的webpack版本不一致,所以我們還是采取這種方式比較穩妥。
寫完之后,我們就可以在terminal輸入npm run build
跑一下,會尷尬地發現報錯了:

這個錯誤告訴我們,需要為.vue文件去聲明一個loader。因為webpack原生是只支持JS文件類型的,並且只支持ES5的語法,所以我們在使用超出它理解范圍的語法的時候,我們要使用一些幫它去處理的工具。所以我們要在webpack.config.js文件里面繼續寫:
module: {
rules: [
{
test: /.vue$/, loader: 'vue-loader' } ] }
添加完這段之后,我們再去terminal執行下npm run build
,你會發現項目根目錄下多了一個dist文件夾,點開里面發現webpack為我們自動打包生成了一個bundle.js文件,感興趣的童鞋可以點開這個js文件看看:


往下翻到100多行左右的時候,你會發現有很多的代碼其實是vue源碼。因為我們項目要依賴vue.js,所以webpack會把vue.js文件打包進來。

你可以通過快捷鍵 command (Ctrl) + F 查找關鍵詞$mount看到,紅線圈住的這段代碼就是我們自己寫的代碼,其實webpack做的工作就是把這些不同的靜態資源的類型打包成一個js,然后我們在html里面引用這個js,就可以正常運行。
相信大家做前端都知道,在做一個項目開發的時候,我們希望把一些零碎的js文件打包到一起,這樣可以減少http請求。同樣的,我們希望使用模塊依賴,因為項目中會做很多可復用的代碼,把它寫到一個模塊里面去,這樣的話當我們再去寫一個新項目的時候,不用再把原來的代碼重新寫一遍,或者是拷貝一份。
當然這里面我們暫時沒有提到.babelrc、.eslintrc、editorconfig、postcss.config.js等,這些我們留到后面再講。
中級前端合理細化目錄篇

初始化工作完成之后,接下來我們要細分目錄了。首先我們需要在項目的根目錄下新建一個文件夾叫build,把webpack的文件單獨放到這個文件夾里面。因為我們項目中會用到很多不同的相關文件的配置,接下來先新建一個 webpack.config.base.js 文件,我們把webpack里面需要用到的共同的配置放到這個base的文件里面。比如開發環境和正式環境,以及后期我們要提到的服務端渲染的環境。我們都依賴於base這個配置。
以下是webpack.config.base.js文件里的代碼:
const path = require('path') const createVueLoaderOptions = require('./vue-loader.config') const isDev = process.env.NODE_ENV === 'development' const config = { target: 'web', entry: path.join(__dirname, '../client/index.js'), output: { filename: 'bundle.[hash:8].js', path: path.join(__dirname, '../dist') }, module: { rules: [ { test: /\.(vue|js|jsx)$/, loader: 'eslint-loader', exclude: /node_modules/, enforce: 'pre' }, { test: /\.vue$/, loader: 'vue-loader', options: createVueLoaderOptions(isDev) }, { test: /\.jsx$/, loader: 'babel-loader' }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }, { test: /\.(gif|jpg|jpeg|png|svg)$/, use: [ { loader: 'url-loader', options: { limit: 1024, name: 'resources/[path][name].[hash:8].[ext]' } } ] } ] } } module.exports = config
然后我們再新建一個 webpack.config.client.js ,這個client文件依賴於base文件,在此基礎上擴展一些其他配置。因此我們需要在webpack.config.client.js里面敲入一行代碼引入base文件 :
const baseConfig = require('./webpack.config.base')
基礎工作做完之后,我們該如何去擴展配置呢?首先在terminal終端命令行安裝下 npm i webpack-merge -D
我們需要webpack-merge這個工具幫助去擴展、合並不同的webpack配置,然后根據聲明好的isDev來判斷應該怎么合並配置。
以下是webpack.config.client.js文件里的代碼:
const path = require('path') const HTMLPlugin = require('html-webpack-plugin') const webpack = require('webpack') const merge = require('webpack-merge') const ExtractPlugin = require('extract-text-webpack-plugin') const baseConfig = require('./webpack.config.base') const isDev = process.env.NODE_ENV === 'development' const defaultPlugins = [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: isDev ? '"development"' : '"production"' } }), new HTMLPlugin() ] const devServer = { port: 8000, host: '0.0.0.0', overlay: { errors: true }, hot: true } let config if (isDev) { // 開發環境的配置 config = merge(baseConfig, { devtool: '#cheap-module-eval-source-map', module: { rules: [ { test: /\.styl/, use: [ 'vue-style-loader', 'css-loader', // { // loader: 'css-loader', // options: { // module: true, // localIdentName: isDev ? '[path]-[name]-[hash:base64:5]' : '[hash:base64:5]' // } // }, { loader: 'postcss-loader', options: { sourceMap: true } }, 'stylus-loader' ] } ] }, devServer, plugins: defaultPlugins.concat([ new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin() ]) }) } else { // 正式環境的配置 config = merge(baseConfig, { entry: { app: path.join(__dirname, '../client/index.js'), vendor: ['vue'] }, output: { filename: '[name].[chunkhash:8].js' }, module: { rules: [ { test: /\.styl/, use: ExtractPlugin.extract({ fallback: 'vue-style-loader', use: [ 'css-loader', { loader: 'postcss-loader', options: { sourceMap: true } }, 'stylus-loader' ] }) } ] }, plugins: defaultPlugins.concat([ new ExtractPlugin('styles.[contentHash:8].css'), new webpack.optimize.CommonsChunkPlugin({ name: 'vendor' }), new webpack.optimize.CommonsChunkPlugin({ name: 'runtime' }) ]) }) } module.exports = config
最后,這個src文件夾我們要重命名一下,叫client,因為我們后期還要寫服務端的代碼,對應的就命名成server,正好對應它的含義。這樣看起來,名稱就變得更加的合理。
當我們萬事大吉的時候,千萬記得要把 webpack.config.base.js 和 webpack.config.client.js 里面的src路徑改掉,換成client,否則就會報錯。

以上就是我們項目最終形成的目錄結構,client目錄下分別有assets、layout、views這三個文件夾,其中assets目錄下放靜態資源,例如images、styles等;layout目錄下放通用布局的組件;views目錄下放具體的業務代碼的組件。
當然,這個目錄其實還可以隨着項目的開發再細分下去,這里就不展開敘述了。
寫在最后
大家一定要注意,在我們正式開發項目、創建一個項目工程的時候,一定要先把目錄結構理順,條理一定要清楚。每個目錄結構里面放什么東西,心里一定要先有個概念。以后新建的文件不要亂放,因為項目一旦做大,維護時間比較久的時候,可能兩三個月里面都有一個文件你不會去碰它。到時候如果要去找一個東西的時候,你會找不到它,這是非常令人難受的一件事情。
最重要的一點是,目錄結構的混亂,會導致你后續開發項目的效率變得非常的低。
這次關於“一個正式項目的目錄結構是怎么形成的”的話題就說到這里,我之后的文章會講些什么呢?文章預告如下:
- eslint的錯誤修復小技巧
- vue-loader是如何配置的
- 如何回答“對vue生命周期的理解”才能讓面試官滿意?
- 淺談css-module的配置
- ......
- 正式環境打包以及異步模塊打包優化