博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Vue+thinkJs博客网站(一)之vue多页面应用的webpack3配置
阅读量:6244 次
发布时间:2019-06-22

本文共 10818 字,大约阅读时间需要 36 分钟。

一.项目简介

    本项目使用vue作为前端框架,thinkJs作为后端框架,构建个人博客网站,页面分为博客展示和后台管理,主要目的是学习使用thinkJs。现在只完成了主要的博客增删改功能,发现webpack的配置遇到了一些坑,这里先记录下。项目目录结构如下:

图片描述

其中system文件夹是前端vue项目的代码,博客展示页面与后台管理页面都在这里,打包成两个页面,具体webpack配置是本文重点。

二.搭建过程

安装nodejs后,首先安装thinkjs

npm install -g think-cli;thinkjs new self_blog;npm install;npm start;

这样thinkJs项目初步搭建完成了,接下来创建vue项目。项目根目录下新建文件夹system。

npm install -g vue-clivue init webpack self_blogcd self_blognpm installnpm run dev

这样vue项目初步搭建完毕,接下来讲下这里vue的具体webpack配置。

三.webpack配置

项目前端页面分为博客的展示和后台管理,这里的思路是将sytem的src下面放后台管理页面,在sytem下新建blog文件夹,放前台展示页面,打包时生成两个html,实现webpack打包多页面应用。目录如下:

图片描述

1.webpack.base.conf.js的配置

使用vue-cli创建项目,npm run dev运行开发环境,会使用webpack-dev-server作为前端服务器,从而实现热加载。这样打包的文件只会在内存里,这里我的思路是直接生成到thinkJs项目的view目录下,通过服务端的路由返回给前端。这样只用启动后端的服务就行了,因为文件已经打包到服务端,前端也不存在跨域访问后端的问题了。所以这里就不需要配置devServer了,而是改变html与js等静态资源的生成目录。首先看下webpack.base.conf.js的代码:

"use strict";const path = require("path");const utils = require("./utils");const config = require("../config");const vueLoaderConfig = require("./vue-loader.conf");const webpack = require("webpack");const baseFileName = require("../package.json").name;const ExtractTextPlugin = require("extract-text-webpack-plugin");const cleanWebpackPlugin = require("clean-webpack-plugin");const AssetsPlugin = require("assets-webpack-plugin");function resolve(dir) {  return path.join(__dirname, "..", dir);}module.exports = {  context: path.resolve(__dirname, "../"),  entry: {    app: "./src/main.js",    blog: "./blog/index.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")    }  },  externals: {    vue: "Vue",    "vue-router": "VueRouter",    echarts: "echarts",    ElementUI: "element-ui"  },  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",        exclude: [resolve("src/icons")],        options: {          limit: 10000,          name: utils.assetsPath(baseFileName + "https://segmentfault.com/img/[name].[hash:7].[ext]")        }      },      {        test: /\.svg$/,        loader: "svg-sprite-loader",        include: [resolve("src")],        options: {          symbolId: "icon-[name]"        }      },      {        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,        loader: "url-loader",        options: {          limit: 10000,          name: utils.assetsPath(baseFileName + "/media/[name].[hash:7].[ext]")        }      },      {        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,        loader: "url-loader",        options: {          limit: 10000,          name: utils.assetsPath(baseFileName + "/fonts/[name].[hash:7].[ext]")        }      }    ]  },  plugins: [    new AssetsPlugin({      filename: "build/webpack.assets.js",      processOutput: function(assets) {        return "window.WEBPACK_ASSETS=" + JSON.stringify(assets);      }    }),    new webpack.optimize.CommonsChunkPlugin({      name: "vendor",      minChunks: function(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 ExtractTextPlugin({      filename: utils.assetsPath(        baseFileName + "/css/[name].[contenthash].css"      ),      allChunks: true    }),    // 编译前删除之前编译生成的静态资源    new cleanWebpackPlugin(["www/static/self_blog", "view/blog"], {      root: resolve("../")    })  ],  node: {    setImmediate: false,    dgram: "empty",    fs: "empty",    net: "empty",    tls: "empty",    child_process: "empty"  }};

首先需要改的是入口文件,因为是多页面应用,需要多个入口文件来保证打包成不同的chunk。我们知道正常vue-cli创建的但页面应用,会打包成三个chunk,分别是vendor.js(第三方依赖),manifest.js(异步加载的实现),app.js(业务代码)。这里新增一个入口文件,打包时就会生成名为blog.js的chunk,含有前台展示页面的js业务代码。

这里新增使用的clean-webpack-plugin,是为了每次编译后,删除之前生成的js,css等静态资源,否则因为这些资源不重名,就会一直堆在你生成的目录下。

此外一些第三方依赖,vue,elementUI什么的,我使用了cdn引入,这样打包时这些依赖不会打进去,进而减小的vendor.js的体积。具体做法就是配置里的externals定义这些依赖,然后在生成html的模板里用script标签直接引入cdn里的js。

注意一下,如果你开发时想用vue-devtool,需要引入vue.js,如果不用就引入vue.min.js。

2.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");const HOST = process.env.HOST;const PORT = process.env.PORT && Number(process.env.PORT);const baseFileName = require("../package.json").name;function resolve(dir) {  return path.join(__dirname, "..", dir);}const devWebpackConfig = merge(baseWebpackConfig, {  module: {    rules: utils.styleLoaders({      sourceMap: config.dev.cssSourceMap,      extract: true,      usePostCSS: true    })  },  // cheap-module-eval-source-map is faster for development  devtool: config.dev.devtool,  output: {    path: resolve(config.dev.assetsRoot),    filename: "static/" + baseFileName + "/js/[name]-[hash:5].js",    chunkFilename: "static/" + baseFileName + "/js/[name]-[id:5].js"  },  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    new HtmlWebpackPlugin({      filename: resolve(`../view/blog/index_index.html`),      template: "./view/index.html",      title: "博客管理系统",      favicon: resolve("favicon.ico"),      inject: true,      chunks: ["manifest", "vendor", "app"]    }),    new HtmlWebpackPlugin({      filename: resolve(`../view/blog/blog_index.html`),      template: "./view/blog.html",      title: "博客展示",      inject: true,      chunks: ["manifest", "vendor", "blog"]    }),    // copy custom static assets    new CopyWebpackPlugin([      {        from: path.resolve(__dirname, "../static"),        to: config.dev.assetsSubDirectory,        ignore: [".*"]      }    ])  ]});module.exports = devWebpackConfig;

这里我删掉了之前默认配置的devSever,以及module.exports直接导出devWebpackConfig。此外,因为打包生成目录的变化,我修改了output里面的path,filename,chunkFilename。使他们生成到self_blog根目录的www/static下面,这也是thinkJs静态资源的默认目录。需要注意下,filename指的是你的出口文件(app),以及通过codespliting生成的js(vendor,manifest)的文件名;chunkFilename定义的是一些懒加载组件打包后的js文件名。

下面需要添加的就是html-webpack-plugin,因为需要打包成两个html,所以使用两次这个插件。除了定义生成文件名(filename),html模板(template)等,还需要定义你这个html需要的chunk,这是跟单页面配置的一个区别。

除此之外,如果你想要开发环境打包时就分离出css,那么在使用utils.styleLoaders时,将extract置为true。因为这里的方法判断是开发环境才使用extract-text-plugin抽离css。

3.webpack.prod.conf.js的配置

prod的配置与dev差不多,生成文件目录也没变,只不过多了一些js,css压缩插件。

"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 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 baseFileName = require("../package.json").name;const env = require("../config/prod.env");function resolve(dir) {  return path.join(__dirname, "..", dir);}const webpackConfig = merge(baseWebpackConfig, {  entry: {    app: "./entry/entry-client-index",    blog: "./entry/entry-client-blog"  },  module: {    rules: utils.styleLoaders({      sourceMap: config.build.productionSourceMap,      extract: true,      usePostCSS: true    })  },  devtool: config.build.productionSourceMap ? config.build.devtool : false,  output: {    path: resolve(config.dev.assetsRoot),    filename: "static/" + baseFileName + "/js/[name]-[chunkhash:5].js",    chunkFilename: "static/" + baseFileName + "/js/[name]-[chunkhash:5].js"  },  plugins: [    new webpack.DefinePlugin({      "process.env": require("../config/prod.env"),      "process.env.VUE_ENV": '"client"'    }),    new UglifyJsPlugin({      uglifyOptions: {        compress: {          warnings: false        }      },      sourceMap: config.build.productionSourceMap,      parallel: true    }),    new webpack.optimize.OccurrenceOrderPlugin(),    new webpack.LoaderOptionsPlugin({      minimize: true    }),    // extract css into its own file    new ExtractTextPlugin({      filename: utils.assetsPath(        baseFileName + "/css/[name].[contenthash].css"      ),      allChunks: true    }),    new HtmlWebpackPlugin({      minify: {},      chunksSortMode: "dependency",      environment: process.env.NODE_ENV,      filename: resolve(`../view/blog/index_index.html`),      template: "./view/index.html",      title: "博客管理系统",      favicon: resolve("favicon.ico"),      inject: true,      chunks: ["manifest", "vendor", "app"]    }),    new HtmlWebpackPlugin({      filename: resolve(`../view/blog/blog_index.html`),      template: "./view/blog.html",      title: "博客展示",      favicon: resolve("favicon.ico"),      inject: true,      chunks: ["manifest", "vendor", "blog"]    }),    // Compress extracted CSS. We are using this plugin so that possible    // duplicated CSS from different components can be deduped.    new OptimizeCSSPlugin({      cssProcessorOptions: config.build.productionSourceMap        ? { safe: true, map: { inline: false } }        : { safe: true }    }),     ]});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")    .BundleAnalyzerPlugin;  webpackConfig.plugins.push(new BundleAnalyzerPlugin());}module.exports = webpackConfig;

四.总结

具体可以看

本次项目主要目的是练习thinkJs,这里先把前期webpack配置方面的东西简单说下,下一篇将会仔细讲下thinkJs的使用方法和特性。项目会继续更新,不少东西还没做完呢。

转载地址:http://ktpia.baihongyu.com/

你可能感兴趣的文章
C++ 对象的内存布局(上)
查看>>
向Java开发者介绍Scala
查看>>
【软考点点】计算机基础知识
查看>>
hdu2066一个人的旅行(多源点多汇点的最短路径问题)
查看>>
老猪带你玩转android自定义控件一——打造最简单viewpagerindicator
查看>>
【hibernate框架】性能优化之list_iterate的不同之处
查看>>
block高级功能
查看>>
把钱投资自己的头脑上(一)
查看>>
iOS调试奇巧淫技(二)之LLDB
查看>>
[LeetCode]173.Binary Search Tree Iterator
查看>>
整合大量开源库项目(五)跳动的TextView JumpingBeans,良好体验的滚动栏ConvenientBanner...
查看>>
some utility discovered by Linux yum search all tcp, epel.repo
查看>>
SecureCRT连接ubuntu时,中文显示乱码的解决方法
查看>>
quartz---我为什么要使用quartz
查看>>
Mybatis参数传递
查看>>
Android 6.0 在运行时请求权限
查看>>
ES6语法(三) 对象
查看>>
Swift4 func
查看>>
create-react-app2.x 自定义配置(less 按需加载 装饰器)
查看>>
第一个掘金文章
查看>>