This article is about 2000 words, it takes about 20 minutes to read it and an hour to try it out
Some time ago, when I did a project, the technology stack was VUE + Webpack, mainly the homepage of the official website and the background management system. According to the situation at that time, I analyzed three schemes
- Two SPA applications (official website and background system) are embedded in one project code.
- Separate two sets of project source code
- A set of project source code on a SPA application
Think about:
- Direct denial of a SPA application in a set of project source code (UI styles will cover each other, if no code specification is difficult to maintain later)
- Two sets of source code, the background may open two ports, and then need to use nGINx reverse proxy may be more troublesome, and front-end development is more troublesome, after all, need to maintain two Git repositories, two sets of Git online process, may take a lot of time.
- I’m (blind) confident in my own technology, and I want to try new things, so it’s not too complicated to figure out what needs to be done. Selected the first solution, which is multiple single page application in a set of source code
The previous multi-page structure diagram
Download the Vue SPA template
npm install vue-cli -g
vue init webpack multiple-vue-amazing
Copy the code
Retrofit multi-page applications
npm install glob --save-dev
Copy the code
Change the directory structure under the SRC folder
/ * this was part of the add -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- start * / / / glob is webpack installation relying on a third-party modules, Var glob = require(var glob = require(var glob = require(var glob = require())'glob'Var HtmlWebpackPlugin = require()'html-webpack-plugin'Var PAGE_PATH = path.resolve(__dirname, __dirname)'.. /src/pages'Var merge = require() var merge = require()'webpack-merge') // Multi-entry configuration // The glob module reads all the js suffix files in the corresponding folder of the Pages folder, if the file exists // then processes exports.entries =function () {
var entryFiles = glob.sync(PAGE_PATH + '/*/*.js')
var map = {}
entryFiles.forEach((filePath) => {
var filename = filePath.substring(filePath.lastIndexOf('/ /') + 1, filePath.lastIndexOf('. '))
map[filename] = filePath
})
return// Read the corresponding HTML suffix from the pages folder and put it in the arrayexport.htmlplugin =function () {
let entryHtml = glob.sync(PAGE_PATH + '/*/*.html')
let arr = []
entryHtml.forEach((filePath) => {
let filename = filePath.substring(filePath.lastIndexOf('/ /') + 1, filePath.lastIndexOf('. '))
letConf = {// template source template: filePath, // filename filename: filename +'.html'// The page template needs to be added with the corresponding JS script chunks. If you do not add this line, each page will be added with all the JS script chunks: ['manifest'.'vendor', filename],
inject: true
}
if (process.env.NODE_ENV === 'production') {
conf = merge(conf, {
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
chunksSortMode: 'dependency'
})
}
arr.push(new HtmlWebpackPlugin(conf))
})
returnArr} / * here is to add some -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * / endCopy the code
Webpack. Base. Conf. Js file
/ * modify part -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - start * / entry: utils. Entries (), / * modify part -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * / endCopy the code
Webpack. Dev. Conf. Js file
This area / * comment file -- -- -- -- -- -- -- -- -- -- -- -- -- start * / / / new HtmlWebpackPlugin ({/ / filename:'index.html',
// template: 'index.html',
// inject: true/ /}), This area / * comment file -- -- -- -- -- -- -- -- -- -- -- -- -- end * / new FriendlyErrorsPlugin () / * add concat (utils. HtmlPlugin ()) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * / ].concat(utils.htmlPlugin())Copy the code
Webpack. Prod. Conf. Js file
/ * comment the contents of this area -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * / / / new HtmlWebpackPlugin ({/ / filename: config. Build. The index, / / the template:'index.html',
// inject: true,
// minify: {
// removeComments: true,
// collapseWhitespace: true,
// removeAttributeQuotes: true
// // more options:
// // https://github.com/kangax/html-minifier#options-quick-reference
// },
// // necessary to consistently work with multiple chunks via CommonsChunkPlugin
// chunksSortMode: 'dependency'/ /}), / * comment the contents of this area -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- end * / / / copy the custom static assets new CopyWebpackPlugin ([{the from: path.resolve(__dirname,'.. /static'),
to: config.build.assetsSubDirectory,
ignore: ['*']}]) / * this location add. Concat (utils. HtmlPlugin ()) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /] concat (utils. HtmlPlugin ())Copy the code
Introduce third-party UI libraries
npm install element-ui bootstrap-vue --save
Copy the code
Introduce different UI index.js for different pages
import BootstrapVue from 'bootstrap-vue'
Vue.use(BootstrapVue)
Copy the code
admin.js
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI)
Copy the code
The above multi-page configuration is a reference to the Internet, and most of the ideas on the Internet are very similar, the core is to change multiple entries, after the configuration is completed, the development can not find the problem, and then about a month of development, after the development of the official website performance analysis found, The webpack-packed Vvendor. Js network loading time is very long, resulting in a very long white screen time of the first screen. Finally, the conclusion is obtained through -webpack-bundle-Analyzer analysis
npm run build --report
Copy the code
solution
Since the loading speed is slow because the vendor is too large, it is good to separate this vendor. I think like this: extract the third-party code used in each page into vendor.js, and then package the third-party code used in each page into their respective vendor-x.js, such as the existing pages index.html and admin.html. Js, vendor-index.js, and vendor-admin.js will be packaged.
Webpack. Prod. Conf. Js file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor-admin',
chunks: ['vendor'],
minChunks: function (module, count) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(path.join(__dirname, '.. /node_modules')) === 0 &&
module.resource.indexOf('element-ui') != -1
)
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor-index',
chunks: ['vendor'],
minChunks: function (module, count) {
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(path.join(__dirname, '.. /node_modules')) === 0 &&
module.resource.indexOf('bootstrap-vue')! = -1)}})Copy the code
Again, everything is fine. Vendor. js is separated into vendor.js, vendor-index, and vendor-admin.js
The solution
HtmlWebpackPlugin has changed chunksSortMode: ‘dependency’ to a custom function configuration, as shown below
Util. Js file
chunksSortMode: function (chunk1, chunk2) {
var order1 = chunks.indexOf(chunk1.names[0])
var order2 = chunks.indexOf(chunk2.names[0])
return order1 - order2
},
Copy the code
Pull out the common-API, a module common between multiple pagesUpdate (2018/4/23)
In fact, the scenario of removing the common files between multiple pages is often used by medium and large projects. At first, I saw the comments below saying that the common API needs to be removed, and I will pack more common-api. CSS, and I have some questions about commonChunk
Requirements: Some common JS and even CSS in the project can be reused on every page. For example, admin.js refers to common-api.js, and index.js refers to common-api.js. Now pull out the common-API module that is common across multiple pages
Adding a Common directory
Create a new common/index.js file that directly references a local js file (I’m using jquery instead of public JS).
Referencing a public file
Reference in admin.js index.js
import $ from '.. /.. /common'
console.log($('body'))
Copy the code
Packaging clearly shows that jquery is packaged twice, wasting resources.
The solution
- Because there are multiple pages, a common entry common-API must be added
- CommonChunkPlugin extracts common-api
- Change the chunks sequence of htmlWebpackPlugin
Webpack ERROR in CommonsChunkPlugin: While running in normal mode it’s not allowed to use a non-entry chunk
At the beginning, a student asked me how to solve this error. At first, I did not know. Later, AFTER looking up some materials, I found that you can solve this error as long as you specify chunks
Respecify the order of htmlplugins in util.js
let chunks = filename === 'admin' ?
['manifest'.'vendor'.'vendor-admin'.'common-api', filename] :
['manifest'.'vendor'.'vendor-index'.'common-api', filename]
Copy the code
The jq is loaded only once, and it is not packaged into common-api. CSS, and the order of scripts in HTML is correct
- Each page loads its own chunk
- Each page has different parameters
- Each page can share the public chunk
- Browser caching for better performance
- If that’s too slow, open gzip
- Pull out the common function common-api per page (updated on 2018/4/23)
feeling
The configuration looks pretty simple, but I thought a lot about it when I was developing it, so if you’re not familiar with CommonsChunkPlugin and HtmlWebpackPlugin, or you only use a third party’s configuration table, you might get stuck. For example,CommonsChunkPlugin does not specify chunks. What is the default? Most people only write a single value for minChunks, but it is the custom function that is the most powerful. In my experience, the combination of chunks and minChunks with custom functions solves almost all of the CommonsChunkPlugin’s magic events.
webpack4
Although this article is based on WebPack3, the idea of webPack4 multi-page configuration and optimized packaging is actually the same.
The source code
This source code like a like
reference
Reference for configuring multiple pages
HtmlWebpackPlugin sequence problem