This is my practical experience with Webpack project construction, the scenario is this, the project is large-scale CMS type, technology selection is Vue, only support chrome, there are many sub-functional modules, all packaged together will have several MB, so the best way is to do multi-entry packaging. The article contains my exploration of the process and webpack in the use of some of the skills, hope to bring reference value for everyone.
First, the project packaging strategy follows several principles:
- Select the appropriate packaging granularity, the resulting single file size should not exceed 500KB
- Take full advantage of browser concurrent requests while ensuring that the number of concurrent calls does not exceed 6
- Make the browser hit 304 as much as possible, frequently changing business code to not package with public code
- Avoid loading too much code that is not in use, and the deeper-layered pages are loaded asynchronously
Based on the above principles, the packaging strategy I chose is as follows:
- Third-party libraries such as Vue, jquery, bootstrap packaged as a file
- Public components such as pop-up windows, menus, etc. packaged as a file
- Tool class, project generic base class packaged as a file
- Each function module packs its own entry file.
- function modules function as a spa, the sub-page is loaded asynchronously
Packaging of each entry file
Because the project is not suitable for the whole as a spa, so each sub-function has a own portal file, my source directory structure is as follows:
Each sub-function is placed under the apps directory, such as question and paper, and the following are the respective sub-pages. The components directory is placed in a common component, which is later.
Since the function module will be added at any time, I can not write the Webpack in the entry of the portal file, so I used a module called GLOB, it can use wildcards to take all the files, as we use Gulp. The code for dynamically fetching the sub-function portal file is as follows:
/* * * Find all portal files dynamically */ var files = Glob.sync ('./public/src/apps/*/index.js '); var newentries = {};files.foreach (function(f) { var name =/.*\/( Apps\/.*?\/index) \.js/.exec (f) [1]; // get a file name like Apps/question/index Newentries[name] == object.assign ({}, Config.entry, newentries);
Webpack packaging After the directory is very messy, if you import file name for question, then the Dist directory will be directly generated a question.xxxxx.js file. However, if the name is Apps/question/index, the corresponding directory structure will be generated. I prefer to build after the directory also has a clear structure, may be accustomed to the gulp of the Hangover bar. This also facilitates uniform operation in the front-end routing. is also a small trick, I generated the directory of the entry files are as follows:
Packing for the third party libraries
Some third-party libraries are used in the project, such as Vue, Vue-router, jquery, Boostrap, and so on. These libraries we basically do not change the source code, and the initial project is basically determined, will not be added. So pack them up together. Of course, this is also to consider the size of not more than 500KB, if you use a large tool like Ueditor, or to be packaged separately.
The configuration file is very simple, with a entry named vendor, such as:
entry: { vendor: [' vue ', ' vue-router ', './public/vendor/jquery/jquery ']},
Whether it's installed with NPM or a library that you put in your project directory is OK, as long as the path is written to the right.
In order to split the third-party library (loaded separately with the <script> tag), we also need to use the Webpack Commonschunkplugin plugin to extract it, so that he will not be packaged with the business code. Code:
new webpack.optimize.CommonsChunkPlugin (' Vendor ');
Packaging of public components
This part of the code processing I was tangled for a long time, because Webpack's packaging ideas are based on the module's dependency tree as the standard for analysis, if a module uses the loading component, then the loading component will be packaged into a module, Unless we explicitly declare the component to load asynchronously in code with require.ensure or AMD-Require plus callbacks, the loading component is packaged separately into a single chunk file.
Neither of the above is what I want, for reasons see the packaging principle at the beginning of the article, packaging all public components together is a natural and reasonable choice, but this is contrary to the spirit of Webpack.
At first I thought of a way to the national salvation, is to build a main.js file in the components directory, the file refers to all the component, so packaging main.js when all the components will be packaged in, Main.js code as follows:
Import loading from './loading.vue './topnav.vue './centernav.vue '; export {loading, TOPNAV, Centernav}
A bit like the feeling of Sass's main file. Use this to write:
Let components = require ('./components/main 'default {components : { = =} require (['./components/main '],function(components) { resolve (components.loading); }) } }}
The disadvantage is that it also has to be written asynchronously, otherwise main.js will be packaged into the business code.
But then I thought, since vendor can, why the components can not be processed in the same way? The best method was found. Also first use glob dynamic find all the components, and then write into the entry, and finally with Commonschunkplugin plug-in stripping out. The code is as follows:
/* dynamically Find all components */ var comps = Glob.sync ('./public/src/components/*.vue '); var compsentry == object.assign ({}, Config.entry, compsentry);
Note that Commonschunkplugin is not to be new and multiple, to be stripped of multiple need to pass the array into, the following wording:
New Webpack.optimize.CommonsChunkPlugin ({ names: [' Vendor ', ' components ']})
As a result, components can be introduced into the page with the <script> tag as well as vendor, which can be introduced at random, and will not be re-packaged into the business code. Such as:
Import loading from './components/loading './components/topnav ';
Shove these files into the entry page.
Previously said our sub-functional modules have their own pages, so we need to introduce these files into these pages, Webpack Htmlwebpackplugin can do this thing, we in the dynamic search for the portal file when the way to do it, the code is as follows:
/** * Dynamically find all portal files*/varFiles = Glob.sync ('./public/src/apps/*/index.js '));varNewentries ={};files.foreach (function(f) {varName =/.*\/(Apps\/.*?\/index) \.js/.exec (f) [1];//get a file name like Apps/question/indexNewentries[name] =F; varPlug =NewHtmlwebpackplugin ({filename:path.resolve (__dirname,‘.. /public/dist/' + name + '. html '), chunks: [' Vendor ', name, ' components '], Template:path.resolve (__dirname,‘.. /public/src/index.html '), inject:true }); Config.plugins.push (plug);});
Asynchronous loading of child pages
Each function module is handled as a spa application, which means that we will dynamically load the corresponding sub-page according to the front-end route, using the official Vue-router is easy to implement, for example, we can write in Question/index.js as follows:
Router.map ({ '/list ': { = = { require (['./list.vue '], resolve); } } , '/edit ': { = = { require (['./edit.vue '], resolve);}} );
In the Webpack configuration file There is no need to write any more, it will automatically package the corresponding chunk file, at this time my dist directory is this:
One thing that makes me wonder is that the asynchronous load of the chunk file does not seem to output the file name, although I configured this in the output parameter: chunkfilename: ' [name]. [Chunkhash].js ', [name] where the output is the ID, it may be related to webpack handling the mechanism of asynchronous chunk, guess. But it does not matter, anyway can be loaded correctly, is the name ugly point.
The above is a general shelf, as I was just beginning to explore Webpack (before the Gulp party), while practicing while sharing it, there are a lot of details can not be detailed, I am in this series of articles slowly.
Webpack: Multi-entry file packaging strategy