Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use Webpack to separate data

2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly shows you "how to use Webpack to separate data", the content is easy to understand, clear, hope to help you solve your doubts, the following let the editor lead you to study and learn "how to use Webpack to separate data" this article.

Developing ways to provide files to users can be a tricky task. There are many different scenarios, different technologies, different terms.

In this article, I want to give you everything you need so that you can:

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

Find out which file segmentation strategy works best for your site and users

Know what to do.

According to Webpack glossary, there are two different types of file segmentation. These terms sound interchangeable, but they are obviously not.

The Webpack file separation consists of two parts, one is Bundle splitting and the other is Code splitting:

Bundle splitting: create more and smaller files and load them in parallel to get a better cache effect. The main function is to make browsers download in parallel and improve the download speed. And using the browser cache, only when the code is modified and the hash value in the file name is changed will it be loaded again.

Code splitting: only load the parts that users need most, the rest of the code follow the lazy loading strategy, the main function is to speed up the loading speed of the page, do not load unnecessary code.

The second one sounds more attractive, doesn't it? In fact, many articles on this issue seem to assume that this is the only worthwhile case for making smaller JavaScript files.

But what I want to tell you here is that * is more valuable on many websites, and it should be something you do for all websites.

Let's find out.

Bundle splitting

The idea behind bundle splitting is very simple: if you have a huge file and change a line of code, the user must download the entire file again. But if you split it into two files, the user only needs to download the changed file, and the browser will provide another file from the cache.

It is worth noting that since bundle splitting is all about caching, it makes no difference for * visits.

(I think too much discussion about performance is about visiting a site * *, partly because "impressions are important" and partly because it's good and easy to measure.

Quantifying the impact of performance enhancements can be tricky for frequent visitors, but we have to quantify it!

This will require a spreadsheet, so we need to lock down a very specific set of environments against which we can test each caching strategy.

This is what I mentioned in the previous paragraph:

Alice visits our website once a week for 10 weeks

We update our website once a week

We update our Product list page every week

We also have a "Product details" page, but we haven't developed it yet

In week 5, we added a new npm package to the site

In week 8, we updated an existing npm package

Some types of people (like me) will try to make the scene as real as possible. Don't do this. The actual situation is not important, we will find out the reason later.

Base line

Assuming that the total capacity of our JavaScript package is 400 KB, we currently load it as a file called main.js.

We have a Webpack configuration as follows (I omitted some extraneous configurations):

/ / webpack.config.js const path = require ('path') module.exports = {entry: path.resolve (_ _ dirame,' src/index.js') output: {path: path.resolve (_ _ dirname, 'dist'), filename:' [name]. [contenthash] .js'}}

For those new cache breaches: whenever I say main.js, I actually mean main.xMePWxHo.js, where the string is a hash of the contents of the file. This means that different file names force browsers to download new files when the code in the application changes.

The contenthash of this package changes every week when we make some new changes to the site. Therefore, Alice visits our site every week and downloads a new 400kb file.

If we turn these events into a table, it will look like this.

That is, in 10 weeks, 4.12 MB, we can do better.

Decompose vendor package

Let's divide the package into main.js and vendor.js files.

/ webpack.config.js const path = require ('path') module.exports = {entry: path.resolve (_ _ dirname,' src/index.js'), output: {path: path.resolve (_ _ dirname, 'dist'), filename:' [name]. [contenthash] .js',}, optimization: {splitChunks: {chunks: 'all'}

Webpack4 does things for you without telling you how to split the package. As a result, we know very little about how webpack is subcontracted, and some people ask, "what on earth are you doing to my package?"

One way to add optimization.splitChunks.chunks = 'all' is to "put everything in node_modules into a file called vendors~main.js."

With this basic bundle splitting,Alice, you still download a new 200kb main.js per visit, but only 200kb's vendor.js (not in this order) is downloaded in *, 8, and 5 weeks.

Total: 2.64 MB.

Reduced by 36%. It's not bad to add five lines of code to our configuration. Do it before you read any further. If you need to upgrade from Webpack 3 to 4, don't worry, it's very simple.

I think this performance improvement seems more abstract because it took place in 10 weeks, but it does reduce the number of bytes for loyal users by 36%, and we should be proud of ourselves.

But we can do better.

Separate each npm package

Our vendor.js encounters the same problem as our main.js file-- a change to part of it means downloading all of it again.

So why not create a separate file for each npm package? It's easy to do.

So split react, lodash, redux, moment, and so on into different files:

Const path = require ('path'); const webpack = require (' webpack') Module.exports = {entry: path.resolve (_ _ dirname, 'src/index.js'), plugins: [new webpack.HashedModuleIdsPlugin (), / / so that file hashes don't change unexpectedly], output: {path: path.resolve (_ _ dirname,' dist'), filename:'[name]. [contenthash] .js',}, optimization: {runtimeChunk: 'single' SplitChunks: {chunks: 'all', maxInitialRequests: Infinity, minSize: 0, cacheGroups: {vendor: {test: / [\\ /] node_ modules [\\ /] /, name (module) {/ / get the name. E.G. Node_modules/packageName/not/this/part.js / / or node_modules/packageName const packageName = module.context.match (/ [\\ /] node_ modules [\ /] (. *?) ([\\ /] | $) /) [1]; / / npm package names are URL-safe, but some servers don't like @ symbols return `npm.$ {packageName.replace ('@',')} ` },},}

The documentation will explain most of the content here well, but I will explain the parts that need to be paid attention to a little bit, because they take me too much time.

Webpack has some less clever default settings, such as splitting output files with a maximum of 3 files and a minimum file size of 30 KB (all smaller files will be concatenated), so I rewrote these.

CacheGroups is where we define the rules for how Webpack should group blocks into output files. There is a module called "vendor" that will be used for any module loaded from node_modules. Usually, you only need to define the name of the output file as a string. But I define name as a function (which will be called for each parsed file). Then return the name of the package from the path of the module. Therefore, we will get a file for each package, such as npm.react-dom.899sadfhj4.js.

The NPM package name must be URL secure to publish, so we don't need encodeURI's packageName. However, I encountered a file with @ (from a scoped package) in the name that the .NET server could not provide, so I replaced @ in this code snippet.

The whole setting is great because it is immutable. No maintenance required-there is no need to reference any packages by name.

Alice still downloads 200 KB of main.js files every week and still downloads 200 KB of npm packages on * visits, but she will never download the same package twice.

Total: 2.24 MB.

It's 44% less than the baseline, which is cool for code that can be copied / pasted from blog posts.

I wonder if it is possible to exceed 50%? There's no problem at all.

Separate the area of the application code

Let's go to the main.js file, which poor Alice downloads again and again.

As I mentioned earlier, we have two different sections on this site: the product list and the product details page. The unique code in each zone is 25 KB (the shared code is 150 KB).

Our product details page has not changed much now, because we have done too much. Therefore, if we treat it as a separate file, we can get it from the cache most of the time.

In addition, our website has a large inline SVG file for rendering icons, which weighs only 25 KB, and this is rarely changed, so we need to optimize it.

We just need to manually add some entry points and tell Webpack to create a file for each item.

Module.exports = {entry: {main: path.resolve (_ _ dirname, 'src/index.js'), ProductList: path.resolve (_ _ dirname,' src/ProductList/ProductList.js'), ProductPage: path.resolve (_ _ dirname, 'src/ProductPage/ProductPage.js'), Icon: path.resolve (_ _ dirname,' src/Icon/Icon.js'),}, output: {path: path.resolve (_ _ dirname 'dist'), filename:' [name]. [contenthash:8] .js',}, plugins: [new webpack.HashedModuleIdsPlugin (), / / so that file hashes don't change unexpectedly], optimization: {runtimeChunk: 'single', splitChunks: {chunks:' all', maxInitialRequests: Infinity, minSize: 0 CacheGroups: {vendor: {test: / [[\ /] node_ modules [\\ /] /, name (module) {/ / get the name. E.G. Node_modules/packageName/not/this/part.js / / or node_modules/packageName const packageName = module.context.match (/ [\\ /] node_ modules [\ /] (. *?) ([\\ /] | $) /) [1]; / / npm package names are URL-safe, but some servers don't like @ symbols return `npm.$ {packageName.replace ('@',')} ` },},}

Webpack also creates files for content shared between ProductList and ProductPage so that we don't get duplicate code.

This will save Alice 50 KB downloads in most cases.

Only 1.815 MB!

We have saved up to 56% of downloads for Alice, which will continue (in our theoretical scenario) until the end of time.

All of this has been changed only in the Webpack configuration-- we haven't made any changes to the application code.

As I mentioned earlier, the exact scenario in the test is not important. This is because no matter what scenario you propose, the conclusion is the same: split the application into reasonable small files so that users can download less code.

Soon, I'll talk about "code splitting"-- another type of file segmentation-- but first I want to solve the three issues you're thinking about right now.

# 1: isn't it slower to have a large number of network requests?

Of course the answer is no.

This used to be the case in the HTTP/1.1 era, but not in the HTTP/2 era.

Still, both the 2016 article and Khan Academy's 2015 article concluded that even with HTTP/2, downloading too many files is slow. But in both articles, "too many" means "hundreds". So remember, if you have hundreds of files, you may encounter concurrency restrictions in the first place.

If you want to know, support for HTTP/2 can be traced back to ie11 on Windows 10. I did a thorough survey, and everyone used an older setting than that, and they unanimously assured me that they didn't care how fast the site loaded.

# 2: is there no overhead / reference code in each webpack package?

Yes, it's true, too.

All right, shit:

More files = more Webpack references

More files = no compression

Let's quantify it so that we know exactly how much to worry about.

Well, I just did a test in which a 190 KB site was split into 19 files, increasing the total number of bytes sent to the browser by about 2%.

Therefore. Increase by 2% during * * visits and decrease by 60% before each visit until the website is taken off the shelves.

The right worry is: none at all.

When I test 1 file to 19, I think I will try it on a number of different networks, including HTTP / 1.1

On 3G and 4G, the site reduced loading time by 30% with 19 files.

This is very messy data. For example, on 4G running No. 2, the site load time is 646ms, and then after running twice, the load time is 1116ms, which is 73% longer than before, and there is no change. As a result, the claim that HTTP/2 is "30 per cent faster" seems a bit furtive.

I created this table to try to quantify the differences made by HTTP/2, but in fact the only thing I can say is that "it may not be significantly different."

What is really surprising are the two lines. That's the old Windows and HTTP/1.1. I bet it will be much slower. I think I need to slow down the Internet a little bit.

I downloaded a Windows 7 virtual machine from Microsoft's website to test these things. It comes with IE8, and I want to upgrade it to IE9, so I went to Microsoft's IE9 download page.

A question about HTTP/2, did you know that it is now built into Node? If you want to try it, I've written a small 100-line HTTP/2 server with gzip, brotli, and response cache.

To satisfy your test fun.

That's all I'm going to say about bundle splitting. I think the only drawback of this approach is that it is possible to constantly convince people to load a large number of small files.

Code splitting (load the code you need)

I said that this special method only makes sense on some websites.

I like to apply the 20plus 20 rule I just made up: if a part of your site is accessed by 20% of users and it is greater than 20% of the site's JavaScript, then you should load the code on demand.

How do you decide?

Suppose you have a shopping site and want to know if the "checkout" code should be separated, because only 30% of visitors will visit it.

The first thing to do is to sell something better.

The second thing is to figure out how much code is completely independent of the checkout function. Since you should always "bundle splitting'" before "code splitting", you probably already know how big this part of the code is.

It may be smaller than you think, so add it before you get too excited. For example, if you have a React site, then your store, reducer, routing, actions, etc., will be shared throughout the site. The only part will be mainly components and their helper classes.

Therefore, you notice that the completely unique code on your checkout page is 7KB. The rest of the site is 300 KB. I would look at this and say, I'm not going to break it up for the following reasons:

Loading ahead of time does not slow down. Remember, you are loading all these files in parallel. See if you can record the load time difference between 300KB and 307KB.

* if you load this code later, the user must wait for the file after clicking "TAKE MY MONEY"-the minimum delay you want.

Code splitting needs to change the application code. It introduces asynchronous logic, which used to be synchronous logic. This is not rocket science, but I think its complexity should be demonstrated by a perceptual user experience.

Let's look at two examples of code splitting.

Polyfills

I'll start with this, because it works for most sites and is a good brief introduction.

I use some strange features on my website, so I have a file that can import all the polyfill I need, including the following eight lines:

/ / polyfills.js require ('whatwg-fetch'); require (' intl'); require ('url-polyfill'); require (' core-js/web/dom-collections'); require ('core-js/es6/map'); require (' core-js/es6/string'); require ('core-js/es6/array'); require (' core-js/es6/object')

Import this file in index.js.

/ / index-always-poly.js import'. / polyfills'; import React from 'react'; import ReactDOM from' react-dom'; import App from'. / App/App'; import'. / index.css'; const render = () = > {ReactDOM.render (, document.getElementById ('root'));} render (); / / yes I am pointless, for now

Using bundle splitting's Webpack configuration, my polyfills is automatically split into four different files because there are four npm packages here. They total about 25 KB, and 90% of browsers don't need them, so it's worth loading them dynamically.

Using the Webpack 4 and import () syntax (not to be confused with the import syntax), it's easy to load polyfill conditionally.

Import React from 'react'; import ReactDOM from' react-dom'; import App from'. / App/App'; import'. / index.css'; const render = () = > {ReactDOM.render (, document.getElementById ('root')) } if ('fetch' in window & &' Intl' in window & & 'URL' in window & &' Map' in window & & 'forEach' in NodeList.prototype & &' startsWith' in String.prototype & & 'endsWith' in String.prototype & &' includes' in String.prototype & & 'includes' in Array.prototype & &' assign' in Object & & 'entries' in Object & &' keys' in Object) {render () } else {import ('. / polyfills') .then (render);}

Reasonable? If all of this content is supported, the page is rendered. Otherwise, import polyfill and render the page. When this code runs in the browser, the Webpack runtime handles the loading of the four npm packages, and when they are downloaded and parsed, render () is called and continues.

By the way, to use import (), you need a dynamic import plug-in for Babel. In addition, as explained in the Webpack documentation, import () uses promises, so you need to populate it separately from other polyfill.

Route-based dynamic loading (specific to React)

Going back to the example of Alice, suppose the site now has an "administration" section where product sellers can log in and manage some useless records they sell.

This section has many wonderful features, a large number of charts, and a large library of charts from npm. Because I'm already doing bundle splittin, I can see that these are shadows of more than 100 KB.

Currently, I have a routing setting that will render when the user views / admin URL. When Webpack packages everything, it finds import AdminPage from'. / AdminPage.js'. And say, "Hey, I need to include this in the initial load."

But we don't want that. We need to put this reference into a dynamically imported administration page, such as import ('. / AdminPage.js'), so that Webpack knows to load it dynamically.

It's very cool and doesn't need to be configured.

So instead of referencing AdminPage directly, I can create another component that will be rendered when the user accesses / admin URL, which might look like this:

/ / AdminPageLoader.js import React from 'react'; class AdminPageLoader extends React.PureComponent {constructor (props) {super (props); this.state = {AdminPage: null,}} componentDidMount () {import ('. / AdminPage'). Then (module = > {this.setState ({AdminPage: module.default});});} render () {const {AdminPage} = this.state Return AdminPage?: Loading...;}} export default AdminPageLoader

The concept is simple, isn't it? When this component is mounted (meaning that the user is at / admin URL), we will dynamically load. / AdminPage.js and then save a reference to the component in the state.

In the render method, we just render the Loading..., while waiting to load or when loading and storing the state.

I think I do this myself just for fun, but in the real world, you just need to use react-loadable, as described in the React documentation on code-splitting.

The above is all the contents of the article "how to use Webpack to separate data". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report