參考一
目錄 一級 二級 bulid 項目構建的一些 js 文件 config 配置文件項,index.js 比較重要,打包上線需要修改配置 dist 項目打包后的文件 node_modules npm安裝包位置 src 項目的開發目錄 - assets 圖片、字體等資源 - components 公共組件部分 - config 開發分支和生產分支的切換配置,以及 fetch.js 對于前后臺數據交互的封裝 - plugin 第三方插件 - views 頁面部分 - server ajax、axios等請求數據集中處理 - router 路由 - store 狀態管理 - App.vue 項目入口文件,我們也可以直接將組建寫這里,而不使用 components 目錄 - main.js 項目的核心文件 index.html html文件 test 測試項目 package.json 項目配置項文件
參考二
基礎庫: vue.js、vue-router、vuex、whatwg-fetch
編譯/打包工具:webpack、babel、node-sass
單元測試工具:karma、mocha、sinon-chai
本地服務器:express目錄結構
README.md 項目介紹
index.html 入口頁面
build 構建腳本目錄build-server.js 運行本地構建服務器,可以訪問構建后的頁面build.js 生產環境構建腳本dev-client.js 開發服務器熱重載腳本,主要用來實現開發階段的頁面自動刷新dev-server.js 運行本地開發服務器utils.js 構建相關工具方法webpack.base.conf.js wabpack基礎配置webpack.dev.conf.js wabpack開發環境配置webpack.prod.conf.js wabpack生產環境配置
config 項目配置dev.env.js 開發環境變量index.js 項目配置文件prod.env.js 生產環境變量test.env.js 測試環境變量
mock mock數據目錄hello.js
package.json npm包配置文件,里面定義了項目的npm腳本,依賴包等信息
src 源碼目錄 main.js 入口js文件app.vue 根組件components 公共組件目錄title.vueassets 資源目錄,這里的資源會被wabpack構建imageslogo.pngroutes 前端路由index.jsstore 應用級數據(state)index.jsviews 頁面目錄hello.vue
static 純靜態資源,不會被wabpack構建。
test 測試文件目錄(unit& e2e)unit 單元測試index.js 入口腳本karma.conf.js karma配置文件specs 單測case目錄Hello.spec.js
參考三
1. build文件夾
( 1 ) build. js'use strict'
require ( './check-versions' ) ( ) process. env. NODE_ENV = 'production'
const ora = require ( 'ora' )
const rm = require ( 'rimraf' )
const path = require ( 'path' )
const chalk = require ( 'chalk' )
const webpack = require ( 'webpack' )
const config = require ( '../config' )
const webpackConfig = require ( './webpack.prod.conf' )
const spinner = ora ( 'building for production...' )
spinner. start ( )
rm ( path. join ( config. build. assetsRoot, config. build. assetsSubDirectory) , err => { if ( err) throw errwebpack ( webpackConfig, ( err, stats) => { spinner. stop ( ) if ( err) throw errprocess. stdout. write ( stats. toString ( { colors: true , modules: false , children: false , chunks: false , chunkModules: false } ) + '\n\n' ) if ( stats. hasErrors ( ) ) { console . log ( chalk. red ( ' Build failed with errors.\n' ) ) process. exit ( 1 ) } console . log ( chalk. cyan ( ' Build complete.\n' ) ) console . log ( chalk. yellow ( ' Tip: built files are meant to be served over an HTTP server.\n' + ' Opening index.html over file:// won\'t work.\n' ) ) } )
} ) ( 2 ) check- versions. js node和npm的版本檢測, 實現版本依賴
'use strict'
const chalk = require ( 'chalk' )
const semver = require ( 'semver' )
const packageConfig = require ( '../package.json' )
const shell = require ( 'shelljs' ) function exec ( cmd) { return require ( 'child_process' ) . execSync ( cmd) . toString ( ) . trim ( )
}
const versionRequirements = [ { name: 'node' , currentVersion: semver. clean ( process. version) , versionRequirement: packageConfig. engines. node }
] if ( shell. which ( 'npm' ) ) { versionRequirements. push ( { name: 'npm' , currentVersion: exec ( 'npm --version' ) , versionRequirement: packageConfig. engines. npm } )
} module . exports = function ( ) { const warnings = [ ] for ( let i = 0 ; i < versionRequirements. length; i++ ) { const mod = versionRequirements[ i] if ( ! semver. satisfies ( mod. currentVersion, mod. versionRequirement) ) { warnings. push ( mod. name + ': ' + chalk. red ( mod. currentVersion) + ' should be ' + chalk. green ( mod. versionRequirement) ) } } if ( warnings. length) { console . log ( '' ) console . log ( chalk. yellow ( 'To use this template, you must update following to modules:' ) ) console . log ( ) for ( let i = 0 ; i < warnings. length; i++ ) { const warning = warnings[ i] console . log ( ' ' + warning) } console . log ( ) process. exit ( 1 ) }
} ( 3 ) utils. js utils是工具的意思,是一個用來處理css的文件,這個文件包含了三個工具函數:
生成靜態資源的路徑
生成 ExtractTextPlugin對象或loader字符串
生成 style- loader的配置
'use strict'
const path = require ( 'path' )
const config = require ( '../config' )
const ExtractTextPlugin = require ( 'extract-text-webpack-plugin' )
const packageConfig = require ( '../package.json' )
exports. assetsPath = function ( _path) { const assetsSubDirectory = process. env. NODE_ENV === 'production' ? config. build. assetsSubDirectory: config. dev. assetsSubDirectory
return path. posix. join ( assetsSubDirectory, _path)
}
exports. cssLoaders = function ( options) { options = options || { } const cssLoader = { loader: 'css-loader' , options: { sourceMap: options. sourceMap} } const postcssLoader = { loader: 'postcss-loader' , options: { sourceMap: options. sourceMap} } function generateLoaders ( loader, loaderOptions) { const loaders = options. usePostCSS ? [ cssLoader, postcssLoader] : [ cssLoader] if ( loader) { loaders. push ( { loader: loader + '-loader' , options: Object. assign ( { } , loaderOptions, { sourceMap: options. sourceMap} ) } ) } if ( options. extract) { return ExtractTextPlugin. extract ( { use: loaders, fallback: 'vue-style-loader' } ) } else { return [ 'vue-style-loader' ] . concat ( loaders) } } return { css: generateLoaders ( ) , postcss: generateLoaders ( ) , less: generateLoaders ( 'less' ) , sass: generateLoaders ( 'sass' , { indentedSyntax: true } ) , scss: generateLoaders ( 'sass' ) , stylus: generateLoaders ( 'stylus' ) , styl: generateLoaders ( 'stylus' ) }
}
exports. styleLoaders = function ( options) { const output = [ ] const loaders = exports. cssLoaders ( options)
for ( const extension in loaders) { const loader = loaders[ extension] output. push ( { test: new RegExp ( '\\.' + extension + '$' ) , use: loader} ) } return output
} exports. createNotifierCallback = ( ) => { const notifier = require ( 'node-notifier' ) return ( severity, errors) => { if ( severity !== 'error' ) return const error = errors[ 0 ] const filename = error. file && error. file. split ( '!' ) . pop ( ) notifier. notify ( { title: packageConfig. name, message: severity + ': ' + error. name, subtitle: filename || '' , icon: path. join ( __dirname, 'logo.png' ) } ) }
} ( 4 ) vue- loader. conf. js 處理. vue文件,解析這個文件中的每個語言塊(template、script、style) ,轉換成js可用的js模塊
'use strict'
const utils = require ( './utils' )
const config = require ( '../config' )
const isProduction = process. env. NODE_ENV === 'production'
const sourceMapEnabled = isProduction? config. build. productionSourceMap: config. dev. cssSourceMap
module . exports = { loaders: utils. cssLoaders ( { sourceMap: sourceMapEnabled, extract: isProduction} ) , cssSourceMap: sourceMapEnabled, cacheBusting: config. dev. cacheBusting, transformToRequire: { video: [ 'src' , 'poster' ] , source: 'src' , img: 'src' , image: 'xlink:href' }
} ( 5 ) webpack. base. conf. js:開發、測試、生產環境的公共基礎配置文件,配置輸出環境,配置模塊resolve和插件等
'use strict'
const path = require ( 'path' )
const utils = require ( './utils' )
const config = require ( '../config' )
const vueLoaderConfig = require ( './vue-loader.conf' )
function resolve ( dir) { return path. join ( __dirname, '..' , dir)
} module . exports = { context: path. resolve ( __dirname, '../' ) , entry: { app: './src/main.js' } , output: { path: config. build. assetsRoot, filename: '[name].js' , publicPath: process. env. NODE_ENV === 'production' ? config. build. assetsPublicPath: config. dev. assetsPublicPath} , resolve: { extensions: [ '.js' , '.vue' , '.json' ] , alias: { 'vue$' : 'vue/dist/vue.esm.js' , '@' : resolve ( 'src' ) , } } , module : { rules: [ { test: /\.vue$/ , loader: 'vue-loader' , options: vueLoaderConfig} , { test: /\.js$/ , loader: 'babel-loader' , include: [ resolve ( 'src' ) , resolve ( 'test' ) , resolve ( 'node_modules/webpack-dev-server/client' ) ] } , { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/ , loader: 'url-loader' , options: { limit: 10000 , name: utils. assetsPath ( 'img/[name].[hash:7].[ext]' ) } } , { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/ , loader: 'url-loader' , options: { limit: 10000 , name: utils. assetsPath ( 'media/[name].[hash:7].[ext]' ) } } , { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/ , loader: 'url-loader' , options: { limit: 10000 , name: utils. assetsPath ( 'fonts/[name].[hash:7].[ext]' ) } } ] } , node: { setImmediate: false , dgram: 'empty' , fs: 'empty' , net: 'empty' , tls: 'empty' , child_process: 'empty' }
}
(6 )webpack. dev. conf. js:webpack配置開發環境中的入口
'use strict'
const utils = require ( './utils' )
const webpack = require ( 'webpack' )
const config = require ( '../config' )
const merge = require ( 'webpack-merge' )
const path = require ( 'path' )
const baseWebpackConfig = require ( './webpack.base.conf' )
const CopyWebpackPlugin = require ( 'copy-webpack-plugin' )
const HtmlWebpackPlugin = require ( 'html-webpack-plugin' )
const FriendlyErrorsPlugin = require ( 'friendly-errors-webpack-plugin' )
const portfinder = require ( 'portfinder' ) const HOST = process. env. HOST
const PORT = process. env. PORT && Number ( process. env. PORT ) const devWebpackConfig = merge ( baseWebpackConfig, { module : { rules: utils. styleLoaders ( { sourceMap: config. dev. cssSourceMap, usePostCSS: true } ) } , devtool: config. dev. devtool, devServer: { clientLogLevel: 'warning' , historyApiFallback: { rewrites: [ { from : /.*/ , to: path. posix. join ( config. dev. assetsPublicPath, 'index.html' ) } , ] , } , hot: true , contentBase: false , compress: true , host: HOST || config. dev. host, port: PORT || config. dev. port, open: config. dev. autoOpenBrowser, overlay: config. dev. errorOverlay? { warnings: false , errors: true } : false , publicPath: config. dev. assetsPublicPath, proxy: config. dev. proxyTable, quiet: true , watchOptions: { poll: config. dev. poll, } } , plugins: [ new webpack. DefinePlugin ( { 'process.env' : require ( '../config/dev.env' ) } ) , new webpack. HotModuleReplacementPlugin ( ) , new webpack. NamedModulesPlugin ( ) , new webpack. NoEmitOnErrorsPlugin ( ) , new HtmlWebpackPlugin ( { filename: 'index.html' , template: 'index.html' , inject: true } ) , new CopyWebpackPlugin ( [ { from : path. resolve ( __dirname, '../static' ) , to: config. dev. assetsSubDirectory, ignore: [ '.*' ] } ] ) ]
} ) module . exports = new Promise ( ( resolve, reject) => { portfinder. basePort = process. env. PORT || config. dev. portportfinder. getPort ( ( err, port) => { if ( err) { reject ( err) } else { process. env. PORT = portdevWebpackConfig. devServer. port = portdevWebpackConfig. plugins. push ( new FriendlyErrorsPlugin ( { compilationSuccessInfo: { messages: [ `Your application is running here: http:// ${ devWebpackConfig. devServer. host} : ${ port} ` ] , } , onErrors: config. dev. notifyOnErrors? utils. createNotifierCallback ( ) : undefined} ) ) resolve ( devWebpackConfig) } } )
} ) (7 )webpack. dev. prod. js:webpack配置生產環境中的入口'use strict'
const path = require ( 'path' )
const utils = require ( './utils' )
const webpack = require ( 'webpack' )
const config = require ( '../config' )
const merge = require ( 'webpack-merge' )
const baseWebpackConfig = require ( './webpack.base.conf' )
const CopyWebpackPlugin = require ( 'copy-webpack-plugin' )
const HtmlWebpackPlugin = require ( 'html-webpack-plugin' )
const ExtractTextPlugin = require ( 'extract-text-webpack-plugin' )
const OptimizeCSSPlugin = require ( 'optimize-css-assets-webpack-plugin' )
const UglifyJsPlugin = require ( 'uglifyjs-webpack-plugin' ) const env = require ( '../config/prod.env' ) const webpackConfig = merge ( baseWebpackConfig, { module : { rules: utils. styleLoaders ( { sourceMap: config. build. productionSourceMap, extract: true , usePostCSS: true } ) } , devtool: config. build. productionSourceMap ? config. build. devtool : false , output: { path: config. build. assetsRoot, filename: utils. assetsPath ( 'js/[name].[chunkhash].js' ) , chunkFilename: utils. assetsPath ( 'js/[id].[chunkhash].js' ) } , plugins: [ new webpack. DefinePlugin ( { 'process.env' : env} ) , new UglifyJsPlugin ( { uglifyOptions: { compress: { warnings: false } } , sourceMap: config. build. productionSourceMap, parallel: true } ) , new ExtractTextPlugin ( { filename: utils. assetsPath ( 'css/[name].[contenthash].css' ) , allChunks: true , } ) , new OptimizeCSSPlugin ( { cssProcessorOptions: config. build. productionSourceMap? { safe: true , map: { inline: false } } : { safe: true } } ) , new HtmlWebpackPlugin ( { filename: config. build. index, template: 'index.html' , inject: true , minify: { removeComments: true , collapseWhitespace: true , removeAttributeQuotes: true } , chunksSortMode: 'dependency' } ) , new webpack. HashedModuleIdsPlugin ( ) , new webpack. optimize. ModuleConcatenationPlugin ( ) , new webpack. optimize. CommonsChunkPlugin ( { name: 'vendor' , minChunks ( module ) { return ( module . resource && /\.js$/ . test ( module . resource) && module . resource. indexOf ( path. join ( __dirname, '../node_modules' ) ) === 0 ) } } ) , new webpack. optimize. CommonsChunkPlugin ( { name: 'manifest' , minChunks: Infinity } ) , new webpack. optimize. CommonsChunkPlugin ( { name: 'app' , async : 'vendor-async' , children: true , minChunks: 3 } ) , new CopyWebpackPlugin ( [ { from : path. resolve ( __dirname, '../static' ) , to: config. build. assetsSubDirectory, ignore: [ '.*' ] } ] ) ]
} ) if ( config. build. productionGzip) { const CompressionWebpackPlugin = require ( 'compression-webpack-plugin' ) webpackConfig. plugins. push ( new CompressionWebpackPlugin ( { asset: '[path].gz[query]' , algorithm: 'gzip' , test: new RegExp ( '\\.(' + config. build. productionGzipExtensions. join ( '|' ) + ')$' ) , threshold: 10240 , minRatio: 0.8 } ) )
} if ( config. build. bundleAnalyzerReport) { const BundleAnalyzerPlugin = require ( 'webpack-bundle-analyzer' ) . BundleAnalyzerPluginwebpackConfig. plugins. push ( new BundleAnalyzerPlugin ( ) )
} module . exports = webpackConfig2. config文件夾
(1 ) dev. env. js和prod. env. js:分別配置:開發環境和生產環境。這個可以根據公司業務結合后端需求配置需要區分開發環境和測試環境的屬性
'use strict'
const merge = require ( 'webpack-merge' )
const prodEnv = require ( './prod.env' ) module . exports = merge ( prodEnv, { NODE_ENV : '"development"'
} ) ps:webpack- merge用于實現合并類似于ES6 的Object. assign ( ) 'use strict'
module . exports = { NODE_ENV : '"production"'
}
(* 注意屬性值要用“‘'”雙層引住),訪問(獲取值)時直接用:process. env. 屬性名ps:process(進程)是nodejs的一個全局變量,process. env 屬性返回一個用戶環境信息的對象(2 )index. js配置解析:'use strict' ;
const path = require ( 'path' ) ; module . exports = { dev: { assetsSubDirectory: 'static' , assetsPublicPath: '/' , proxyTable: { } , host: 'localhost' , port: 3030 , autoOpenBrowser: true , errorOverlay: true , notifyOnErrors: true , poll: false , devtool: 'cheap-module-eval-source-map' , cacheBusting: true , cssSourceMap: true } , build: { index: path. resolve ( __dirname, '../dist/index.html' ) , assetsRoot: path. resolve ( __dirname, '../dist' ) , assetsSubDirectory: 'static' , assetsPublicPath: '/' , productionSourceMap: true , devtool: '#source-map' , productionGzip: false , productionGzipExtensions: [ 'js' , 'css' ] , bundleAnalyzerReport: process. env. npm_config_report }
} ; 3 、node_modules文件夾:
存放npm install時根據package . json配置生成的npm安裝包的文件夾4 、src文件夾:
我們需要在src文件夾中開發代碼,打包時webpack會根據build中的規則(build規則依賴于config中的配置)將src打包壓縮到dist文件夾在瀏覽器中運行
(1 )assets文件:用于存放靜態資源(css、image),assets打包時路徑會經過webpack中的file- loader編譯(因此,assets需要使用絕對路徑)成js
(2 )components文件夾:用來存放 . vue 組件 ( 實現復用等功能,如:過濾器,列表項等)
(3 )router文件夾:在router/ index. js文件中配置頁面路由
(4 )App. vue:是整個項目的主組件,所有頁面都是通過使用< router- view/ > 開放入口在App. vue下進行切換的(所有的路由都是App. vue的子組件)
(5 )main. js:入口js文件(全局js,你可以在這里:初始化vue實例、require / import 需要的插件、注入router路由、引入store狀態管理)5 、static 文件夾:
webpack默認存放靜態資源(css、image)的文件夾,與assets不同的是:static 在打包時會直接復制一個同名文件夾到dist文件夾里(不會經過編譯,可使用相對路徑)6 、其他文件:
(1 ). babelrc:瀏覽器解析的兼容配置,該文件主要是對預設(presets)和插件(plugins)進行配置,因此不同的轉譯器作用不同的配置項,大致可分為:語法轉義器、補丁轉義器、sx和flow插件
(2 ). editorconfig:用于配置代碼格式(配合代碼檢查工具使用,如:ESLint,團隊開發時可統一代碼風格),這里配置的代碼規范規則優先級高于編輯器默認的代碼格式化規則 。
(3 ). gitignore:配置git提交時需要忽略的文件
(4 )postcssrc. js: autoprefixer(自動補全css樣式的瀏覽器前綴);postcss- import (@import 引入語法)、CSS Modules(規定樣式作用域)
(5 )index. html:項目入口頁面,編譯之后所有代碼將插入到這來
(6 )package . json:npm的配置文件(npm install根據package . json下載對應版本的安裝包)
(7 )package . lock. json:npm install(安裝)時鎖定各包的版本號
(8 )README . md:項目使用說明