《从零搭建 vue2 vue-router2 webpack3 工程》详细介绍了搭建的工程的步骤,本文主要介绍如何在此基础上来改造为多入口。
多入口指的是 webpack 配置项 entry 配置为包含多个 key 的数组或者对象,即 MPA(multiple entry points),那么什么情况下会配置多入口?一般用 vue 大部分是做 SPA(one entry point),因为 SPA 能更好的配合 vue-router,那么我个人想到了几个可能的场景,下面将结合设想的场景来说明如何配置。
Github地址:github.com/qinshenxue/…
场景一对应分支mpa1场景二对应分支mpa2
前台页面和后台管理页面都放在一起,目录结构如下(在《从零搭建 vue2 vue-router2 webpack3 工程》的工程目录上改造)。
- mpa1
- |---- build
- |---- src
- |---- admin // 后台管理
- | |---- views
- | |---- app.vue
- | |---- main.js
- | |---- router.js
- |
- |---- web // 移动端
- |---- views
- |---- app.vue
- |---- main.js
- |---- router.js
当然也可以认为就是两个独立的模块,各自都有一套前端路由,只是模块之间存在很多公共的第三方库。对于这种结构,我们希望最终生产构建能够达到以下目标:
上述目标用目录表示如下。
- mpa1
- |---- src
- |---- dist
- |---- web
- | |---- index.html
- |
- |---- admin
- | |---- index.html
- |
- |---- assets
- |---- js
- | |---- manifest.js
- | |---- vendor.js
- | |---- web-vendor.js
- | |---- admin-vendor.js
- | |---- web.js
- | |---- admin.js
- |
- |---- css
- |---- web-vendor.css
- |---- admin-vendor.css
- |---- web.css
- |---- admin.css
下面开始一步一步调整配置,最终达成上面所有的目标。
首先当然要在 webpack.base.config.js 添加 web 和 admin 的入口。
- entry: {
- web: path.resolve(__dirname, '../src/web/main.js'),
- admin: path.resolve(__dirname, '../src/admin/main.js')
- }
无论是提取各个入口的公共模块(例如 vue、vue-router ),还是提取 web 和 admin 各自引入的第三方库,都只需要用 webpack 自带的插件 webpack.optimize.CommonsChunkPlugin。
先将 web 和 admin 各自引入的第三方模块提取到 vendor。
- [
- new webpack.optimize.CommonsChunkPlugin({
- name: 'web-vendor',
- chunks: ['web'],
- minChunks: function (module) {
- return module.context && module.context.indexOf("node_modules") !== -1;
- }
- }),
- new webpack.optimize.CommonsChunkPlugin({
- name: 'admin-vendor',
- chunks: ['admin'],
- minChunks: function (module) {
- return module.context && module.context.indexOf("node_modules") !== -1;
- }
- })
- ]
接着将 web-vendor 和 admin-vendor 中公共的模块提取为 vendor。
- [
- // ...
- new webpack.optimize.CommonsChunkPlugin({
- name: 'vendor',
- chunks: ['admin-vendor', 'web-vendor']
- })
- ]
最后提取 vendor 中的 webpack 模块加载部分的代码。
- [
- // ...
- new webpack.optimize.CommonsChunkPlugin({
- name: 'manifest',
- chunks: ['vendor']
- })
- ]
CSS 提取采用 extract-text-webpack-plugin 插件。但是配置不需要那么复杂。
- [
- new ExtractTextPlugin({
- allChunks: true,
- filename: "css/[name].css?[contenthash:8]"
- })
- ]
那么如何提取 web 和 admin 引入的第三方库的 CSS 呢?其实在上面配置 web-vendor 和 admin-vendor 的时候就完成了。
生成页面采用 html-webpack-plugin。不同于单入口,需要手动配置 chunks,chunks 配置每个入口依赖的“模块”(chunk)。
- [
- new HtmlWebpackPlugin({
- filename: path.resolve(__dirname, `../dist/web/index.html`),
- template: 'index.tpl.html',
- chunks: ['manifest', 'vendor', 'web-vendor', 'web'],
- inject: true
- }),
- new HtmlWebpackPlugin({
- filename: path.resolve(__dirname, `../dist/admin/index.html`),
- template: 'index.tpl.html',
- chunks: ['manifest', 'vendor', 'admin-vendor', 'admin'],
- inject: true
- })
- ]
以上就是所有的配置,满足了所有我们希望达到的构建目标。可以 git clone 文章开头给出的 github 地址尝试一下,注意要切换到分支 mpa1。
不用端路由,采用后端路由,页面可能是 php、jsp、aspx,实际开发中这种情况也比较多。这种有点像使用了常用模块加载库(seajs,requirejs)一样,每个页面都需要引入自己的依赖项。目录结构如下。
- mpa2
- |---- build
- |---- src
- |---- css
- |---- images
- |---- pages
- |---- moduleA
- | |---- index.vue
- | |---- index.js
- |
- |---- moduleB
- | |---- index.vue
- | |---- index.js
- |
- |---- moduleC
- |---- index.vue
- |---- index.js
对于这种结构,构建目标和场景一类似,具体如下。
- entry: {
- moduleA: resolve('../src/pages/moduleA/index.js'),
- moduleB: resolve('../src/pages/moduleB/index.js'),
- moduleC: resolve('../src/pages/moduleC/index.js')
- }
当你模块特别多的时候,这样写肯定不好维护,可以自己写一个函数来生成。
- [
- new webpack.optimize.CommonsChunkPlugin({
- name: 'vendor',
- chunks: ['moduleA', 'moduleB', 'moduleC'],
- minChunks: function (module) {
- return module.context && module.context.indexOf("node_modules") !== -1;
- }
- }),
- new webpack.optimize.CommonsChunkPlugin({
- name: 'manifest',
- chunks: ['vendor']
- })
- ]
css 提取和场景一相同,就不再说明了。
这里我把生成页面的改为函数生成。
- var isProd = process.env.NODE_ENV === "production";
- exports.genHtmlPlugins = function () {
- var baseWebpackConfig = require('./webpack.base.config');
- var path = require('path')
- var plugins = [];
- Object.keys(baseWebpackConfig.entry).forEach(function (name) {
- plugins.push(
- new HtmlWebpackPlugin({
- filename: isProd ? path.resolve(__dirname, `../dist/${name}/index.html`) : `${name}/index.html`,
- template: 'index.tpl.html',
- chunks: isProd ? ['manifest','vendor', name] : [name],
- inject: true
- }))
- })
- return plugins
- }
上面的函数区分了当前环境,开发环境下,filename 配置为
,对应访问地址为
- 入口名/index.html
,开发模式下也不需要用到 CommonsChunkPlugin,因此 chunks 只有一个,而在生产构建时,需要指定 chunks。
- http://localhost:8090/moduleA/
最终构建后的目录结构如下。
- mpa2
- |---- src
- |---- dist
- |---- moduleA
- | |---- index.html
- |
- |---- moduleB
- | |---- index.html
- |
- |---- moduleC
- | |---- index.html
- |
- |---- assets
- |---- js
- | |---- manifest.js
- | |---- vendor.js
- | |---- moduleA.js
- | |---- moduleB.js
- | |---- moduleC.js
- |
- |---- css
- |---- vendor.css
- |---- moduleA.css
- |---- moduleB.css
- |---- moduleC.css
上述两个场景的配置大同小异,实际上就是通过 CommonsChunkPlugin 和 HtmlWebpackPlugin 这两个插件来完成你想要的目标。
来源: https://juejin.im/entry/5a04f819f265da43310d4687