摘要:簡(jiǎn)單項(xiàng)目腳手架地址使用技術(shù)棧需要學(xué)習(xí)的知識(shí)內(nèi)容相當(dāng)多,尤其是教程,官方腳手架雖然相當(dāng)完整齊全,但是修改起來還是挺花時(shí)間,于是自己參照網(wǎng)上的資料和之前做過的項(xiàng)目用到的構(gòu)建工具地去寫了一個(gè)簡(jiǎn)單項(xiàng)目腳手架。
簡(jiǎn)單vue項(xiàng)目腳手架 github地址 使用技術(shù)棧
需要學(xué)習(xí)的知識(shí)webpack(^2.6.1)
webpack-dev-server(^2.4.5)
vue(^2.3.3)
vuex(^2.3.1)
vue-router(^2.5.3)
vue-loader(^12.2.1)
eslint(^3.19.0)
vue.js
vuex
vue-router
vue-loader
webpack2
eslint
內(nèi)容相當(dāng)多,尤其是webpack2教程,官方腳手架vue-cli雖然相當(dāng)完整齊全,但是修改起來還是挺花時(shí)間,于是自己參照網(wǎng)上的資料和之前做過的項(xiàng)目用到的構(gòu)建工具地去寫了一個(gè)簡(jiǎn)單vue項(xiàng)目腳手架。適用于多頁面spa模式的業(yè)務(wù)場(chǎng)景(每個(gè)模塊都是一個(gè)spa)。比較簡(jiǎn)單,主要就是一個(gè)webpack.config.js文件,沒有說特意地去劃分成分webpack.dev.config.js、webpack.prov.config.js等等。下面是整個(gè)webpack.config.js文件代碼:
const { resolve } = require("path") const webpack = require("webpack") const HtmlWebpackPlugin = require("html-webpack-plugin") const ExtractTextPlugin = require("extract-text-webpack-plugin") const glob = require("glob") module.exports = (options = {}) => { // 配置文件,根據(jù) run script不同的config參數(shù)來調(diào)用不同config const config = require("./config/" + (process.env.npm_config_config || options.config || "dev")) // 遍歷入口文件,這里入口文件與模板文件名字保持一致,保證能同時(shí)合成HtmlWebpackPlugin數(shù)組和入口文件數(shù)組 const entries = glob.sync("./src/modules/*.js") const entryJsList = {} const entryHtmlList = [] for (const path of entries) { const chunkName = path.slice("./src/modules/".length, -".js".length) entryJsList[chunkName] = path entryHtmlList.push(new HtmlWebpackPlugin({ template: path.replace(".js", ".html"), filename: "modules/" + chunkName + ".html", chunks: ["manifest", "vendor", chunkName] })) } // 處理開發(fā)環(huán)境和生產(chǎn)環(huán)境ExtractTextPlugin的使用情況 function cssLoaders(loader, opt) { const loaders = loader.split("!") const opts = opt || {} if (options.dev) { if (opts.extract) { return loader } else { return loaders } } else { const fallbackLoader = loaders.shift() return ExtractTextPlugin.extract({ use: loaders, fallback: fallbackLoader }) } } const webpackObj = { entry: Object.assign({ vendor: ["vue", "vuex", "vue-router"] }, entryJsList), // 文件內(nèi)容生成哈希值chunkhash,使用hash會(huì)更新所有文件 output: { path: resolve(__dirname, "dist"), filename: options.dev ? "static/js/[name].js" : "static/js/[name].[chunkhash].js", chunkFilename: "static/js/[id].[chunkhash].js", publicPath: config.publicPath }, externals: { }, module: { rules: [ // 只 lint 本地 *.vue 文件,需要安裝eslint-plugin-html,并配置eslintConfig(package.json) { enforce: "pre", test: /.vue$/, loader: "eslint-loader", exclude: /node_modules/ }, /* http://blog.guowenfh.com/2016/08/07/ESLint-Rules/ http://eslint.cn/docs/user-guide/configuring [eslint資料] */ { test: /.js$/, exclude: /node_modules/, use: ["babel-loader", "eslint-loader"] }, // 需要安裝vue-template-compiler,不然編譯報(bào)錯(cuò) { test: /.vue$/, loader: "vue-loader", options: { loaders: { sass: cssLoaders("vue-style-loader!css-loader!sass-loader", { extract: true }) } } }, { // 需要有相應(yīng)的css-loader,因?yàn)榈谌綆炜赡軙?huì)有文件 // (如:element-ui) css在node_moudle // 生產(chǎn)環(huán)境才需要code抽離,不然的話,會(huì)使熱重載失效 test: /.css$/, use: cssLoaders("style-loader!css-loader") }, { test: /.(scss|sass)$/, use: cssLoaders("style-loader!css-loader!sass-loader") }, { test: /.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(?.+)?$/, use: [ { loader: "url-loader", options: { limit: 10000, name: "static/imgs/[name].[ext]?[hash]" } } ] } ] }, plugins: [ ...entryHtmlList, // 抽離css new ExtractTextPlugin({ filename: "static/css/[name].[chunkhash].css", allChunks: true }), // 抽離公共代碼 new webpack.optimize.CommonsChunkPlugin({ names: ["vendor", "manifest"] }), // 定義全局常量 // cli命令行使用process.env.NODE_ENV不如期望效果,使用不了,所以需要使用DefinePlugin插件定義,定義形式""development""或JSON.stringify("development") new webpack.DefinePlugin({ "process.env": { NODE_ENV: options.dev ? JSON.stringify("development") : JSON.stringify("production") } }) ], resolve: { // require時(shí)省略的擴(kuò)展名,不再需要強(qiáng)制轉(zhuǎn)入一個(gè)空字符串,如:require("module") 不需要module.js extensions: [".js", ".json", ".vue", ".scss", ".css"], // require路徑簡(jiǎn)化 alias: { "~": resolve(__dirname, "src"), // Vue 最早會(huì)打包生成三個(gè)文件,一個(gè)是 runtime only 的文件 vue.common.js,一個(gè)是 compiler only 的文件 compiler.js,一個(gè)是 runtime + compiler 的文件 vue.js。 // vue.js = vue.common.js + compiler.js,默認(rèn)package.json的main是指向vue.common.js,而template 屬性的使用一定要用compiler.js,因此需要在alias改變vue指向 vue: "vue/dist/vue" }, // 指定import從哪個(gè)目錄開始查找 modules: [ resolve(__dirname, "src"), "node_modules" ] }, // 開啟http服務(wù),publicPath => 需要與Output保持一致 || proxy => 反向代理 || port => 端口號(hào) devServer: config.devServer ? { port: config.devServer.port, proxy: config.devServer.proxy, publicPath: config.publicPath, stats: { colors: true } } : undefined, // 屏蔽文件超過限制大小的warn performance: { hints: options.dev ? false : "warning" }, // 生成devtool,保證在瀏覽器可以看到源代碼,生產(chǎn)環(huán)境設(shè)為false devtool: "inline-source-map" } if (!options.dev) { webpackObj.devtool = false webpackObj.plugins = (webpackObj.plugins || []).concat([ // 壓縮js new webpack.optimize.UglifyJsPlugin({ // webpack2,默認(rèn)為true,可以不用設(shè)置 compress: { warnings: false } }), // 壓縮 loaders new webpack.LoaderOptionsPlugin({ minimize: true }) ]) } return webpackObj }上面的代碼對(duì)于每個(gè)配置項(xiàng)都有注釋說明,這里有幾點(diǎn)需要注意的: 1. webpack.config.js導(dǎo)出的是一個(gè)function
之前項(xiàng)目的webpack.config.js是以對(duì)象形式export的,如下
module.exports = { entry: ..., output: { ... }, ... }
而現(xiàn)在倒出來的是一個(gè)function,如下:
module.exports = (options = {}) => { return { entry: ..., output: { ... }, ... } }
這樣的話,function會(huì)在執(zhí)行webpack CLI的時(shí)候獲取webpack的參數(shù),通過options傳進(jìn)function,看一下package.json:
"local": "npm run dev --config=local", "dev": "webpack-dev-server -d --hot --inline --env.dev --env.config dev", "build": "rimraf dist && webpack -p --env.config prod" //rimraf清空dist目錄
對(duì)于local命令,我們執(zhí)行的是dev命令,但是在最后面會(huì)--config=local,這是配置,這樣我們可以通過process.env.npm_config_config獲取到,而對(duì)于dev命令,對(duì)于--env XXX,我們便可以在function獲取option.config= "dev" 和 option.dev= true的值,特別方便!以此便可以同步參數(shù)來加載不同的配置文件了。對(duì)于-d、-p不清楚的話,可以這里查看,很詳細(xì)!
// 配置文件,根據(jù) run script不同的config參數(shù)來調(diào)用不同config const config = require("./config/" + (process.env.npm_config_config || options.config || "dev"))2. modules放置模板文件、入口文件、對(duì)應(yīng)模塊的vue文件
將入口文件和模板文件放到modules目錄(名字保持一致),webpack文件會(huì)通過glob讀取modules目錄,遍歷生成入口文件對(duì)象和模板文件數(shù)組,如下:
const entries = glob.sync("./src/modules/*.js") const entryJsList = {} const entryHtmlList = [] for (const path of entries) { const chunkName = path.slice("./src/modules/".length, -".js".length) entryJsList[chunkName] = path entryHtmlList.push(new HtmlWebpackPlugin({ template: path.replace(".js", ".html"), filename: "modules/" + chunkName + ".html", chunks: ["manifest", "vendor", chunkName] })) }
對(duì)于HtmlWebpackPlugin插件中幾個(gè)配置項(xiàng)的意思是,template:模板路徑,filename:文件名稱,這里為了區(qū)分開來模板文件我是放置在dist/modules文件夾中,而對(duì)應(yīng)的編譯打包好的js、img(對(duì)于圖片我們是使用file-loader、url-loader進(jìn)行抽離,對(duì)于這兩個(gè)不是很理解的,可以看這里)、css我也是會(huì)放在dist/下對(duì)應(yīng)目錄的,這樣目錄會(huì)比較清晰。chunks:指定插入文件中的chunk,后面我們會(huì)生成manifest文件、公共vendor、以及對(duì)應(yīng)生成的jscss(名稱一樣)
3. 處理開發(fā)環(huán)境和生產(chǎn)環(huán)境ExtractTextPlugin的使用情況開發(fā)環(huán)境,不需要把css進(jìn)行抽離,要以style插入html文件中,可以很好實(shí)現(xiàn)熱替換
生產(chǎn)環(huán)境,需要把css進(jìn)行抽離合并,如下(根據(jù)options.dev區(qū)分開發(fā)和生產(chǎn)):
// 處理開發(fā)環(huán)境和生產(chǎn)環(huán)境ExtractTextPlugin的使用情況 function cssLoaders(loader, opt) { const loaders = loader.split("!") const opts = opt || {} if (options.dev) { if (opts.extract) { return loader } else { return loaders } } else { const fallbackLoader = loaders.shift() return ExtractTextPlugin.extract({ use: loaders, fallback: fallbackLoader }) } } ... // 使用情況 // 注意:需要安裝vue-template-compiler,不然編譯會(huì)報(bào)錯(cuò) { test: /.vue$/, loader: "vue-loader", options: { loaders: { sass: cssLoaders("vue-style-loader!css-loader!sass-loader", { extract: true }) } } }, ... { test: /.(scss|sass)$/, use: cssLoaders("style-loader!css-loader!sass-loader") }
再使用ExtractTextPlugin合并抽離到static/css/目錄
4. 定義全局常量cli命令行(webpack -p)使用process.env.NODE_ENV不如期望效果,使用不了,所以需要使用DefinePlugin插件定義,定義形式""development""或JSON.stringify(process.env.NODE_ENV),我使用這樣的寫法"development",結(jié)果報(bào)錯(cuò)(針對(duì)webpack2),查找了一下網(wǎng)上資料,它是這樣講的,可以去看一下,設(shè)置如下:
new webpack.DefinePlugin({ "process.env": { NODE_ENV: options.dev ? JSON.stringify("development") : JSON.stringify("production") } })5. 使用eslint修正代碼規(guī)范
通過eslint來檢查代碼的規(guī)范性,通過定義一套配置項(xiàng),來規(guī)范代碼,這樣多人協(xié)作,寫出來的代碼也會(huì)比較優(yōu)雅,不好的地方是,就是配置項(xiàng)太多,有些默認(rèn)項(xiàng)設(shè)置我們不需要,但是確是處處限制我們,需要通過配置屏蔽掉,可以通過.eslintrc 文件或是package.json的eslintConfig,還有其他方式,可以到中文網(wǎng)看,這里我用的是package.json方式,如下:
... "eslintConfig": { "parser": "babel-eslint", "extends": "enough", "env": { "browser": true, "node": true, "commonjs": true, "es6": true }, "rules": { "linebreak-style": 0, "indent": [2, 4], "no-unused-vars": 0, "no-console": 0 }, "plugins": [ "html" ] }, ...
我們還需要安裝 npm install eslint eslint-config-enough eslint-loader --save-dev,eslint-config-enough是所謂的配置文件,這樣package.json的內(nèi)容才能起效,但是不當(dāng)當(dāng)是這樣,對(duì)應(yīng)編輯器也需要安裝對(duì)應(yīng)的插件,sublime text 3需要安裝SublimeLinter、SublimeLinter-contrib-eslint插件。對(duì)于所有規(guī)則的詳解,可以去看官網(wǎng),也可以去這里看,很詳細(xì)!
由于我們使用的是vue-loader,自然我們是希望能對(duì).vue文件eslint,那么需要安裝eslint-plugin-html,在package.json中進(jìn)行配置。然后對(duì)應(yīng)webpack配置:
{ enforce: "pre", test: /.vue$/, loader: "eslint-loader", exclude: /node_modules/ }
我們會(huì)發(fā)現(xiàn)webpack v1和v2之間會(huì)有一些不同,比如webpack1對(duì)于預(yù)先加載器處理的執(zhí)行是這樣的,
module: { preLoaders: [ { test: /.js$/, loader: "eslint-loader" } ] }
更多的不同可以到中文網(wǎng)看,很詳細(xì),不做拓展。
6. alias vue指向問題... alias: { vue: "vue/dist/vue" }, ...
Vue 最早會(huì)打包生成三個(gè)文件,一個(gè)是 runtime only 的文件 vue.common.js,一個(gè)是 compiler only 的文件 compiler.js,一個(gè)是 runtime + compiler 的文件 vue.js。
vue.js = vue.common.js + compiler.js,默認(rèn)package.json的main是指向vue.common.js,而template 屬性的使用一定要用compiler.js,因此需要在alias改變vue指向
之前的項(xiàng)目中使用的是用express啟動(dòng)http服務(wù),webpack-dev-middleware+webpack-hot-middleware,這里會(huì)用到compiler+compilation,這個(gè)是webpack的編譯器和編譯過程的一些知識(shí),也不是很懂,后續(xù)要去做做功課,應(yīng)該可以加深對(duì)webpack運(yùn)行機(jī)制的理解。這樣做的話,感覺復(fù)雜很多,對(duì)于webpack2.0 devServer似乎功能更強(qiáng)大更加完善了,所以直接使用就可以了。如下:
devServer: { port: 8080, //端口號(hào) proxy: { //方向代理 /api/auth/ => http://api.example.dev "/api/auth/": { target: "http://api.example.dev", changeOrigin: true, pathRewrite: { "^/api": "" } } }, publicPath: config.publicPath, stats: { colors: true } } //changeOrigin會(huì)修改HTTP請(qǐng)求頭中的Host為target的域名, 這里會(huì)被改為api.example.dev //pathRewrite用來改寫URL, 這里我們把/api前綴去掉,直接使用/auth/請(qǐng)求
webpack 2 打包實(shí)戰(zhàn)講解得非常好,非常棒。可以去看一下,一定會(huì)有所收獲!
8. 熱重載原理webpack中文網(wǎng),講的還算清楚,不過可能太笨,看起來還是云里霧里的,似懂非懂的,補(bǔ)補(bǔ)課,好好看看。
9. localtunnel的使用Localtunnel 是一個(gè)可以讓內(nèi)網(wǎng)服務(wù)器暴露到公網(wǎng)上的開源項(xiàng)目,使用可以看這里,
$ npm install -g localtunnel $ lt --port 8080 your url is: https://uhhzexcifv.localtunnel.me
這樣的話,可以把我們的本地網(wǎng)站暫時(shí)性地暴露到公網(wǎng),可以對(duì)網(wǎng)站做一些線上線下對(duì)比,詳細(xì)內(nèi)容可以去了解一下localtunnel,這里講的是通過上面配置,訪問https://uhhzexcifv.localtunnel.me,沒有達(dá)到理想效果,出現(xiàn)了Invalid Host header的錯(cuò)誤,因?yàn)閐evServer缺少一個(gè)配置disableHostCheck: true,這樣的一個(gè)配置,很多文檔上面都沒有說明,字面上面的意思不要去檢查Host,這樣設(shè)置,便可以繞過這一層檢驗(yàn),設(shè)置的配置項(xiàng)在optionsSchema.json中,issue可以看這里
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/87014.html
摘要:提前申明注意自己對(duì)腳手架的理解和認(rèn)識(shí),很多東西和理解都是形象上的手法,并不專業(yè)和官方一種項(xiàng)目構(gòu)建工具,可以將和壓縮成一個(gè)文件。之后使用項(xiàng)目名進(jìn)入項(xiàng)目根目錄,使用來自動(dòng)安裝項(xiàng)目依賴。 提前申明 注意:自己對(duì)vue腳手架的理解和認(rèn)識(shí),很多東西和理解都是形象上的手法,并不專業(yè)和官方 webpack 一種項(xiàng)目構(gòu)建工具,可以將css和js壓縮成一個(gè)文件。此外,可以提供測(cè)試用服務(wù)器。使用webpa...
摘要:那該怎么管理這兩個(gè)不同的項(xiàng)目呢解決子模塊用的的同學(xué)肯定一下子就想到子模塊的知識(shí)了。最后,也希望有想法的同學(xué)還有大佬多多留言,給點(diǎn)建議原文地址從零開始做前端架構(gòu)腳手架參考資料官方文檔使用定制前端腳手架別人寫的腳手架文件操作相關(guān)文檔子模塊 前言 相信很多人都用過vue-cli或create-react-app或者類似的腳手架。腳手架方便我們復(fù)制,粘貼,或者clone代碼庫,而且還可以更具用...
摘要:可以譯作運(yùn)行時(shí)過程全面分析和解析,這個(gè)全面分析涉及到比較基礎(chǔ)的或者復(fù)雜的重要前端概念和中的概念等。注本篇是運(yùn)行時(shí)全解析系列文章的第一篇,首次發(fā)表于,友善轉(zhuǎn)載蟹蟹。附更多內(nèi)容請(qǐng)參考核心維護(hù)者蔣豪群同學(xué)的的公開課視頻 Vue Runtime Full Analysis - VueCLI3 Get Start VRFA: (Vue Runtime Full Analysis) 可以譯作vue...
摘要:的外表,的心說在前面對(duì)于我個(gè)人來說,一個(gè)好的腳手架有助于我們心無旁騖地去學(xué)習(xí)一些庫例如和。所以說,為什么不弄個(gè)的呢我的想法就是將和盡量保持一致,除了它們的核心和。并不會(huì)對(duì)該文件夾下的文件進(jìn)行處理。 react-webpack-boilerplate vue-cli的外表,React的心 說在前面 對(duì)于我個(gè)人來說,一個(gè)好的腳手架有助于我們心無旁騖地去學(xué)習(xí)一些庫例如Vue和React。vu...
摘要:然后類似一樣我的命名是可以在頁面的任何地方使用,如果你對(duì)具體的實(shí)現(xiàn)方法有興趣,歡迎點(diǎn)擊本文結(jié)尾的鏈接,去我的倉庫上查看。 前言 最近收到一個(gè)這樣的需求,要求做一個(gè)基于 vue 和 element-ui 的通用后臺(tái)框架頁,具體要求如下: 要求通用性高,需要在后期四十多個(gè)子項(xiàng)目中使用,所以大部分地方都做成可配置的. 要求做成腳手架的形式.可以 npm 安裝 要求實(shí)現(xiàn)多頁簽,并且可以通過瀏...
摘要:然后類似一樣我的命名是可以在頁面的任何地方使用,如果你對(duì)具體的實(shí)現(xiàn)方法有興趣,歡迎點(diǎn)擊本文結(jié)尾的鏈接,去我的倉庫上查看。 前言 最近收到一個(gè)這樣的需求,要求做一個(gè)基于 vue 和 element-ui 的通用后臺(tái)框架頁,具體要求如下: 要求通用性高,需要在后期四十多個(gè)子項(xiàng)目中使用,所以大部分地方都做成可配置的. 要求做成腳手架的形式.可以 npm 安裝 要求實(shí)現(xiàn)多頁簽,并且可以通過瀏...
閱讀 2026·2021-10-11 10:59
閱讀 1130·2021-09-07 09:59
閱讀 2295·2021-08-27 16:17
閱讀 2847·2019-08-30 15:54
閱讀 2332·2019-08-30 12:58
閱讀 1836·2019-08-30 12:53
閱讀 1526·2019-08-28 18:13
閱讀 797·2019-08-26 13:35