摘要:到多頁應用前言我有一個創建的項目,但是我想做成多頁應用,怎么辦,廢話不多說,直接開擼約定新增代碼部分在和中間刪除注釋代碼部分在和中間,很多東西都寫在注釋里第一步一個項目新建一個項目官網默認使用的服務,這個服務是做不了單頁的,需要手動建一
vue-cli到多頁應用
前言:我有一個cli創建的vue項目,但是我想做成多頁應用,怎么辦,廢話不多說,直接開擼~
約定:新增代碼部分在//add和//end中間 刪除(注釋)代碼部分在//del和//end中間,很多東西都寫在注釋里
第一步:cli一個vue項目新建一個vue項目 官網 vue init webpack demo
cli默認使用webpack的dev-server服務,這個服務是做不了單頁的,需要手動建一個私服叫啥你隨意 一般叫dev.server或者dev.client
進入剛剛創建vue項目 cd demo
在目錄下面找到build/utils.js文件
修改部分:
utils.js
"use strict" const path = require("path") const config = require("../config") const ExtractTextPlugin = require("extract-text-webpack-plugin") const packageConfig = require("../package.json") //add const glob = require("glob"); const HtmlWebpackPlugin = require("html-webpack-plugin"); //功能:生成html文件及js文件并把js引入html const pagePath = path.resolve(__dirname, "../src/views/"); //頁面的路徑,比如這里我用的views,那么后面私服加入的文件監控器就會從src下面的views下面開始監控文件 //end 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 } } // generate loader string to be used with extract text plugin 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 }) }) } // Extract CSS when that option is specified // (which is the case during production build) if (options.extract) { return ExtractTextPlugin.extract({ use: loaders, fallback: "vue-style-loader" }) } else { return ["vue-style-loader"].concat(loaders) } } // https://vue-loader.vuejs.org/en/configurations/extract-css.html return { css: generateLoaders(), postcss: generateLoaders(), less: generateLoaders("less"), sass: generateLoaders("sass", { indentedSyntax: true }), scss: generateLoaders("sass"), stylus: generateLoaders("stylus"), styl: generateLoaders("stylus") } } // Generate loaders for standalone style files (outside of .vue) 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") }) } } //add 新增一個方法處理入口文件(單頁應用的入口都是寫死,到時候替換成這個方法) exports.createEntry = () => { let files = glob.sync(pagePath + "/**/*.js"); let entries = {}; let basename; let foldername; files.forEach(entry => { // Filter the router.js basename = path.basename(entry, path.extname(entry), "router.js"); foldername = path.dirname(entry).split("/").splice(-1)[0]; // If foldername not equal basename, doing nothing // The folder maybe contain more js files, but only the same name is main if (basename === foldername) { entries[basename] = process.env.NODE_ENV === "development" ? [ "webpack-hot-middleware/client?noInfo=true&reload=true&path=/__webpack_hmr&timeout=20000", entry ]: [entry]; } }); return entries; }; //end //add 新增出口文件 exports.createHtmlWebpackPlugin = (publicModule) => { let files = glob.sync(pagePath + "/**/*.html", {matchBase: true}); let entries = exports.createEntry(); let plugins = []; let conf; let basename; let foldername; publicModule = publicModule || []; files.forEach(file => { basename = path.basename(file, path.extname(file)); foldername = path.dirname(file).split("/").splice(-1).join(""); if (basename === foldername) { conf = { template: file, filename: basename + ".html", inject: true, chunks: entries[basename] ? [basename] : [] }; if (process.env.NODE_ENV !== "development") { conf.chunksSortMode = "dependency"; conf.minify = { removeComments: true, collapseWhitespace: true, removeAttributeQuotes: true }; // 在構建生產環境時,需要指定共用模塊 conf.chunks = [...publicModule, ...conf.chunks]; } plugins.push(new HtmlWebpackPlugin(conf)); } }); return plugins; }; //end第三步:創建私服(不使用dev-server服務,自己建一個)
從express新建私服并配置(build文件夾下新建 我這里叫webpack.dev.client.js)
webpack.dev.client.js
/** * created by qbyu2 on 2018-05-30 * express 私服 * */ "use strict"; const fs = require("fs"); const path = require("path"); const express = require("express"); const webpack = require("webpack"); const webpackDevMiddleware = require("webpack-dev-middleware"); //文件監控(前面配置了從views下面監控) const webpackHotMiddleware = require("webpack-hot-middleware"); //熱加載 const config = require("../config"); const devWebpackConfig = require("./webpack.dev.conf"); const proxyMiddleware = require("http-proxy-middleware"); //跨域 const proxyTable = config.dev.proxyTable; const PORT = config.dev.port; const HOST = config.dev.host; const assetsRoot = config.dev.assetsRoot; const app = express(); const router = express.Router(); const compiler = webpack(devWebpackConfig); let devMiddleware = webpackDevMiddleware(compiler, { publicPath: devWebpackConfig.output.publicPath, quiet: true, stats: { colors: true, chunks: false } }); let hotMiddleware = webpackHotMiddleware(compiler, { path: "/__webpack_hmr", heartbeat: 2000 }); app.use(hotMiddleware); app.use(devMiddleware); Object.keys(proxyTable).forEach(function (context) { let options = proxyTable[context]; if (typeof options === "string") { options = { target: options }; } app.use(proxyMiddleware(context, options)); }); //雙路由 私服一層控制私服路由 vue的路由控制該頁面下的路由 app.use(router) app.use("/static", express.static(path.join(assetsRoot, "static"))); let sendFile = (viewname, response, next) => { compiler.outputFileSystem.readFile(viewname, (err, result) => { if (err) { return (next(err)); } response.set("content-type", "text/html"); response.send(result); response.end(); }); }; //拼接方法 function pathJoin(patz) { return path.join(assetsRoot, patz); } /** * 定義路由(私服路由 非vue路由) * */ // favicon router.get("/favicon.ico", (req, res, next) => { res.end(); }); // http://localhost:8080/ router.get("/", (req, res, next)=>{ sendFile(pathJoin("index.html"), res, next); }); // http://localhost:8080/home router.get("/:home", (req, res, next) => { sendFile(pathJoin(req.params.home + ".html"), res, next); }); // http://localhost:8080/index router.get("/:index", (req, res, next) => { sendFile(pathJoin(req.params.index + ".html"), res, next); }); module.exports = app.listen(PORT, err => { if (err){ return } console.log(`Listening at http://${HOST}:${PORT} `); })
私服創建好了 安裝下依賴
有坑。。。
webpack和熱加載版本太高太低都不行
npm install webpack@3.10.0 --save-dev
npm install webpack-dev-middleware --save-dev
npm install webpack-hot-middleware@2.21.0 --save-dev
npm install http-proxy-middleware --save-dev
webpack.base.conf.js
把原來寫死的 entry: { app: "./src/index.js" }, 改為: entry: utils.createEntry(),
webpack.dev.conf.js
"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") process.env.NODE_ENV = "development"; 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 }) }, // cheap-module-eval-source-map is faster for development devtool: config.dev.devtool, // these devServer options should be customized in /config/index.js //del 注掉SPA的服務器 // devServer: { // clientLogLevel: "warning", // historyApiFallback: { // rewrites: [ // { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, "index.html") }, // ], // }, // hot: true, // contentBase: false, // since we use CopyWebpackPlugin. // 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, // necessary for FriendlyErrorsPlugin // watchOptions: { // poll: config.dev.poll, // } // }, //end plugins: [ new webpack.DefinePlugin({ "process.env": require("../config/dev.env") }), new webpack.HotModuleReplacementPlugin(), new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. new webpack.NoEmitOnErrorsPlugin(), // https://github.com/ampedandwired/html-webpack-plugin //del 注釋掉spa固定的單頁出口 末尾動態配上出口 // new HtmlWebpackPlugin({ // filename: "index.html", // template: "index.html", // inject: true // }), //end // copy custom static assets new CopyWebpackPlugin([ { from: path.resolve(__dirname, "../static"), to: config.dev.assetsSubDirectory, ignore: [".*"] } ]) ] //add .concat(utils.createHtmlWebpackPlugin()) //end }) //del // module.exports = new Promise((resolve, reject) => { // portfinder.basePort = process.env.PORT || config.dev.port // portfinder.getPort((err, port) => { // if (err) { // reject(err) // } else { // // publish the new Port, necessary for e2e tests // process.env.PORT = port // // add port to devServer config // devWebpackConfig.devServer.port = port // // // Add FriendlyErrorsPlugin // devWebpackConfig.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) // } // }) // }) //end module.exports = devWebpackConfig;
webpack.prod.conf.js
plugins最后加上.concat(utils.createHtmlWebpackPlugin(["manifest", "vendor"]))
test環境一樣
scripts下面"dev":
這樣執行的時候就不會走默認的dev-server而走你的私服了
"scripts": { "dev": "node build/webpack.dev.client.js", "start": "npm run dev", "build": "node build/build.js" },第六步:創建測試文件
src目錄下新建 views文件夾 (代碼注釋里有 當時配的目錄跟這個一致就可以 隨便你命名 遵循命名規范就行)
views 文件夾下新建兩個文件夾index和home 代表多頁 每頁多帶帶一個文件夾 文件夾下建對應文件
打包改為相對路徑config/index.js
build下面
assetsPublicPath: "/", => assetsPublicPath: "./",
最后,npm run dev 或者 npm run build
測試環境自己配 跟 生產環境差不多,就幾個配置參數不一樣這個時候你會發現,特么的什么鬼文章 報錯了啊
稍安勿躁~
兩個地方,
1.webpack.dev.client.js
//雙路由 私服一層控制私服路由 vue的路由控制該頁面下的路由 app.use(router) app.use("/static", express.static(path.join(assetsRoot, "static")));
這個assetsRoot cli創建的時候是沒有的 在config/index.js 下面找到dev加上
assetsRoot: path.resolve(__dirname, "../dist"),
2.還是版本問題
webpack-dev-middleware 默認是3.1.3版本但是會報錯
具體哪個版本不報錯我也不知道
context.compiler.hooks.invalid.tap("WebpackDevMiddleware", invalid);
找不到invalid 源碼里面是有的
卸載webpack-dev-middleware
npm uninstall webpack-dev-middleware
使用dev-server自帶的webpack-dev-middleware (cli單頁應用是有熱加載的)
重新install dev-server
npm install webpack-dev-server@2.10.0 --save-dev
npm run dev總結:核心點就在創建并配置私服和修改出口入口配置,坑就在版本不兼容
建議:cli一個vue的demo項目 從頭擼一遍 再在實際項目里使用,而不是copy一下運行沒問題搞定~
建議而已,你怎么打人,嗚嗚嗚~
快過節了,覺得本文對你有用的話請隨意打賞,讓作者可以買個棒棒糖吃~
-------------------------------------------6.1更-----------------------------------------
留了一個坑,一天了,有贊有收藏,沒見人評論指出坑,心痛的無法呼吸~
build 后 沒有引入共用模塊
代碼已更新~ build后可正常訪問...
代碼倉庫:github
注:內容有不當或者錯誤處請指正~轉載請注明出處~謝謝合作!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107860.html
摘要:哪吒別人的看法都是狗屁,你是誰只有你自己說了才算,這是爹教我的道理。哪吒去他個鳥命我命由我,不由天是魔是仙,我自己決定哪吒白白搭上一條人命,你傻不傻敖丙不傻誰和你做朋友太乙真人人是否能夠改變命運,我不曉得。我只曉得,不認命是哪吒的命。 showImg(https://segmentfault.com/img/bVbwiGL?w=900&h=378); 出處 查看github最新的Vue...
摘要:淺談秒殺系統架構設計后端掘金秒殺是電子商務網站常見的一種營銷手段。這兩個項目白話網站架構演進后端掘金這是白話系列的文章。 淺談秒殺系統架構設計 - 后端 - 掘金秒殺是電子商務網站常見的一種營銷手段。 不要整個系統宕機。 即使系統故障,也不要將錯誤數據展示出來。 盡量保持公平公正。 實現效果 秒殺開始前,搶購按鈕為活動未開始。 秒殺開始時,搶購按鈕可以點擊下單。 秒殺結束后,按鈕按鈕變...
摘要:多個單頁應用整合的工程的開發環境工程的目錄設置本文內容的工程的目錄設計基于的多個單頁應用的開發環境搭建目錄一開發環境使用二需求分析三開發思路四目錄設計及思路五開發環境開發六整個開發環境的目錄注釋一開發環境使用多終端頁面路徑設置 vue-multi-device-single-page 多個單頁應用整合的vue工程的開發環境vue工程的目錄設置 showImg(https://segme...
摘要:另外備注一部分參數的說明折疊有助于文檔樹中文本節點的空白區域對進行壓縮默認默認按照不同文件的依賴關系來排序。敲黑板講重點的當然目前這部分的文檔在官網還不是很全,所以這里我們參考了印記中文的說明文檔,指優化模塊。 鏈接 寫在前面 為什么要自己手寫一個腳手架? 如何去思考遇到的問題? 正文 鏈接 原文鏈接 github whale-vue ——寫在前面 1、為什么要自己手寫...
閱讀 1418·2021-09-22 15:52
閱讀 1458·2019-08-30 15:44
閱讀 895·2019-08-30 14:24
閱讀 2705·2019-08-30 13:06
閱讀 2700·2019-08-26 13:45
閱讀 2782·2019-08-26 13:43
閱讀 1014·2019-08-26 12:01
閱讀 1436·2019-08-26 11:56