Is webpack packing too slow? Try bundleless

Time:2021-7-22

Introduction:Webpack packages and integrates various resources to form a bundle. When there are more and more resources, the process of packaging will be slower and slower. What if we don’t need to pack? Can the quality be improved by allowing the browser to load the corresponding resources directly? This paper shares the relevant ideas, core technology points and implementation of vite of browser based esmodule to realize the local development of bundless, as well as the landing practice in the scenario of Ali supply chain POS.

Is webpack packing too slow? Try bundleless

Introduction

Webpack first appeared to solve the problems of front-end modularization and the use of node. JS ecology. In the past eight years, the ability of webpack has become more and more powerful.

Is webpack packing too slow? Try bundleless

However, with the growth of the project, the speed of packaging construction is getting slower and slower. Every time you start, you have to wait for dozens of seconds or even a few minutes, and then start a round of construction optimization. With the further increase of the project, the construction speed will decrease and fall into the cycle of continuous optimization.

Is webpack packing too slow? Try bundleless

When the project reaches a certain scale, the benefits of building optimization based on bundle become more and more limited, and can not achieve quality improvement. From another point of view, the main reason why webpack is slow is that it packages and integrates various resources to form a bundle. If we do not need the bundle packaging process and let the browser directly load the corresponding resources, we may be able to jump out of this cycle and achieve quality improvement.

Is webpack packing too slow? Try bundleless

Under the bundleless architecture, we no longer need to build a complete bundle. At the same time, when modifying a file, the browser only needs to reload a single file. Without building this layer, we will be able to achieve the following goals:

  • Extremely fast local startup speed, only need to start local service.
  • Extremely fast code compilation speed, only need to deal with a single file each time.
  • The time complexity of project development and construction is always o (1), so that the project can continue to maintain efficient construction.
  • More simple debugging experience, no longer strong dependence on sourcemaps, can achieve stable single file debug.

Based on the above possibilities, bundleless will redefine the local development of the front-end, and let us rediscover the experience that the front-end can take effect immediately after modifying a single file 10 years ago. At the same time, with the hotmodulereplace technology of the front-end, we can save the refresh and finally save it.

A very important basic ability to realize bundleless is the dynamic loading ability of modules. There are two main ideas for this

  • The advantage of ES module loader like system. JS is its high compatibility.
  • It directly uses the web standard esmodule to face the future, and the overall architecture is simpler.

In the local development process, the impact of compatibility is not particularly great. At the same time, esmodule has covered more than 90% of browsers. We can fully use the ability of esmodule to let browsers load the required modules independently, so as to achieve bundleless at a lower cost and for the future.

Many esmodule based development tools have emerged in the community in recent years, such as vite, snowpack, ES dev server, etc. This paper will mainly share the relevant ideas and core technology points of browser based esmodule ability to realize bundless local development, as well as the related implementation of vite and the landing practice in the supply chain POS scenario.

Second, the difference between bundle and bundleless from the perspective of resource loading

Let’s take the most familiar create react app default project as an example to compare the difference between bundle and bundleless from the actual page rendering resource loading process.

Is webpack packing too slow? Try bundleless

Bundle development mode based on webpack

Is webpack packing too slow? Try bundleless

The specific module loading mechanism in the above figure can be simplified as the following figure:

Is webpack packing too slow? Try bundleless

Repackaging when the project starts and files change, which makes the project start and secondary construction need to do more things, and the corresponding time-consuming will also increase.

Based on esmodule bundleless mode

Is webpack packing too slow? Try bundleless

As can be seen from the above figure, there is no longer a built bundle or chunk file, but a local corresponding file is loaded directly.

Is webpack packing too slow? Try bundleless

As can be seen from the above figure, under the bundleless mechanism, the project can be started only by starting a server to accept the browser’s request. At the same time, when the file changes, it only needs to process the changed file additionally, and other files can be read directly in the cache.

Comparative summary

Is webpack packing too slow? Try bundleless

Bundleless mode can make full use of the browser’s self loading feature, skip the packaging process, so that we can get a very fast startup speed when the project starts, and only need to recompile a single file when the local update. Next, we will share how to develop bundleless based on the capabilities of browser esmodule.

How to realize bundleless

How to use esmodule to load

The first step to implement bundleless is to let the browser load the corresponding module independently.

Open esmodule with type = “module”

<div id="root"></div>
<script type="module">
  //You can use esmodule directly by using type = "module" in the script tag
  import React from 'https://cdn.pika.dev/react'
  import ReactDOM from 'https://cdn.pika.dev/react-dom'

  ReactDOM.render('Hello World', document.getElementById('root'))
</script>

Using import maps to support bar import

Share a standard of import maps that has been implemented in chrome. We can directly use the writing method of import react from ‘react’. In the future, we can use this ability to implement online bundleless deployment.

<div id="root"></div>
<!--  Open chrome://flags/#enable -experimental-productivity-features --> 
<script type="importmap">
  {
    "imports": {
      "react": "https://cdn.pika.dev/react",
      "react-dom": "https://cdn.pika.dev/react-dom"
    }
  }
</script>
<script type="module">
  //Support bar import
  import React from 'react'
  import ReactDOM from 'react-dom'

  ReactDOM.render('Hello World!', document.getElementById('root'))
</script>

Above, we introduced how to use the native esmodule in browser. For the local development scenario, we only need to start a local devserver to carry the browser’s request, map it to the corresponding local file, and dynamically point the resource path of import in the project to our local address, so that the browser can directly load the local file. For example, we can use the following writing method to direct the entry JS file to the local path, Then devserver intercepts the corresponding request and returns the corresponding file.

<div id="root"></div>
<!--  Direct to local path -- >
<script type="module"></script>

How to load non JS file resources

Through esmodule, we can load JS independently with the help of browser, but in actual project code, we will not only import JS file, but also have the following writing method:

// main.jsx
import React from 'react'
import ReactDOM from 'react-dom'
Import '. / index. CSS' // import CSS file
Import app from '. / APP' // import JSX file

//Using JSX syntax
ReactDOM.render(<App />, document.getElementById('root'))

The browser processes files according to the content type, and does not care about the specific file type. Therefore, when the browser initiates a request, we need to convert the corresponding resources to esmodule format, set the corresponding content type to JS, and return it to the browser for execution. The browser will parse the files according to the JS syntax. The overall process is shown in the following figure:

Is webpack packing too slow? Try bundleless

The following is the implementation of vite. In the process of request return, different files are processed dynamically:

Is webpack packing too slow? Try bundleless

How to implement hotmodulereplace

Hotmodulereplace can take effect directly in the current scenario without refreshing the page after we modify the code. Combined with the extremely fast effective speed of bundleless, we can realize the experience of saving and taking effect without delay. For react, it can only be implemented by using react hot loader in the webpack scenario. However, this block is limited by the specific implementation, and some scenarios may have bugs. The author also suggests migrating to react refresh implemented by the react team, but there is no corresponding implementation in webpack. In the bundleless scenario, because each of our components is loaded independently, to integrate react refresh, we only need to add corresponding scripts at the top and bottom of the file when the browser requests to return.

Is webpack packing too slow? Try bundleless

To completely implement hotmodulereplace will be more complex than the above. It also needs a set of dependency analysis mechanism to determine which files to replace and whether to reload when a file changes. In the bundleless scenario, because we no longer need to package as a complete bundle, and we can modify a single file more flexibly, the implementation of this block will be easier.

Here are the related implementations in vite:

Is webpack packing too slow? Try bundleless

How to optimize a large number of requests leading to slow page loading

Bundleless mode is no longer packaged, which improves the startup speed. However, for some modules with more external dependencies or a large number of their own files, a large number of requests need to be made to obtain all the resources, which will reduce the page loading time in the development process. For example, the following is how to import lodash es directly in the browser and send out a large number of requests:

Is webpack packing too slow? Try bundleless

In this area, we can do the corresponding optimization to package the external dependence into a single file in advance to reduce the excessive network requests caused by excessive external dependence in the development process.

In the start process of vite, there is a vite optimize process, which will automatically package the dependencies in package.json into ES6 module with rollup.

Is webpack packing too slow? Try bundleless

Is webpack packing too slow? Try bundleless

In addition to improving the loading speed of the page, with the help of @ rollup / plugin commonjs, we can package the external dependencies of commonjs in the form of esmodule to further expand the application scope of bundleless.

IV. implementation practice under the scenario of supply chain POS

Our team is responsible for the supply chain POS business, which can be divided into the home decoration industry for building materials and home furnishings and the retail industry for offline stores. In terms of technical architecture, we adopted the independent development of each domain bundle, and finally merged into a large spa with the help of the underlying SDK. Due to the complexity of the project, in the daily development process, there are some pain points as follows:

  • The start-up and time-consuming of the project is relatively long.
  • It takes a long time to compile after modification.
  • Lack of stable HMR capability, the development process needs to create scenarios repeatedly.
  • Debug relies on the ability of sourcemaps, sometimes it is unstable.

Based on the above problems, with the help of vite’s related implementation, we have tried and implemented bundleless in the local development environment, which has greatly improved the local development experience in some experimental projects.

It can greatly improve the speed of startup and modification

At present, the development of single bundle dimension has been realized

Is webpack packing too slow? Try bundleless

Webpack

Is webpack packing too slow? Try bundleless.gif”)

Vite Bundleless

As can be seen from the above, when starting a single bundle, webpack takes about 10 seconds, while vite based on bundleless only takes about 1 second, which is 10 times higher.

Is webpack packing too slow? Try bundleless

The overall page loading time is about 4S, which is still shorter than the packaging and construction time of webpack. At the same time, from the above video, we can see that the speed of HMR reaches millisecond level response, which realizes the basic senseless saving and takes effect.

Debugging a single file without relying on sourcemap

Is webpack packing too slow? Try bundleless

Problems and solutions in landing process

In the actual landing process, the main problems are that the relevant modules do not meet the esmodule specification and some writing standardization

  • Some modules are not packaged with esmodule.
  • Less depends on node_ The specification of the writing method of modules.
  • JSX file suffix specification.
  • Babel runtime processing.

Some modules are not packaged with esmodule

For packages without esmodule package output or with wrong output, different policies are used according to different types

  • Internal package: release a new version of the package with esmodule by upgrading the scaffolding.
  • External dependence: through the forms of issue and pull request, it promotes the upgrade of number precision and other modules.
  • At the same time, due to historical reasons, some packages that cannot be printed as esmodules can be packaged as esmodules with the help of @ rollup / plugin commonjs.

Less depends on node_ The standard of writing modules

@import '[email protected]/pos-style-mixin/style/lst.less'; 
//It only supports less loader in webpack, but not in native less

//Unified migration to the following mode
@import '@ali/pos-style-mixin/style/lst.less';

//At the same time, configure lessoptions in the less laoder of the original webpack build for the final packaging
/*
{
    loader: 'less-loader',
        options: {
            lessOptions: {
                javascriptEnabled: true,
                paths: [path.resolve(cwd, 'node_modules')],
            }
        }
}
*/

JSX file suffix specification

In the process of running, vite compiles files according to different suffixes. In webpack mode, we usually leave JSX, JS and other files to Babel loader for processing, which makes some files that were originally JSX do not write JSX suffixes. Vite is only good at / (TSX| JSX) $/ file for esbuild compilation, for pure JS will directly skip the esbuild process. In this case, we will gradually migrate the wrong file that did not write JSX to JSX file.

Processing of Babel runtime

After using Babel plugin transform runtime, the packaged output will be as follows:
Is webpack packing too slow? Try bundleless

The @ Babel / Runtime / helpers / extensions quoted above is in the form of commonjs and cannot be used directly. In this case, there are two solutions:

1) For internally packaged modules, you can add usemodules configuration during ES6 packaging, so that the packaged code will directly refer to @ Babel / Runtime / helpers / ESM / extensions

Is webpack packing too slow? Try bundleless

2) For the modules with high repackaging cost, we can use vite’s plug-in mechanism to convert @ Babel / Runtime / helpers to @ Babel / Runtime / helpers / ESM at runtime, which can be implemented through alias configuration

Is webpack packing too slow? Try bundleless

The above is the sharing of some problems encountered in the migration process of vite development environment and the handling, and the larger scale landing of this piece is still in progress. The implementation of bundleless is not only to adapt to vite’s development mode, but also to standardize the code of each module in the future. We can implement our modules as standard esmodules, and use lower cost when new tools and ideas appear.

Fifth, the feasibility of using bundleless to deploy directly

Due to the speed of network request and browser parsing, bundle can bring more benefits in loading speed for larger applications. In 2018, V8 also gave relevant performance suggestions: use in local development and small web applications. In today’s scenario, with the continuous improvement of browser and network performance, combined with caching capabilities such as serviceworker, the impact of network loading is getting smaller and smaller. For some scenarios that do not need to consider compatibility issues, you can try to deploy the code loaded through esmodule directly.

Vi. summary

This paper mainly shares how to improve the R & D efficiency and implementation ideas of the front end under the bundleless architecture, as well as the implementation practice in specific business scenarios. Bundleless essentially gives the work of module dependency analysis in the original webpack to the browser, which reduces the code conversion in the development process, greatly improves the construction speed in the development process, and makes better use of the related development tools of the browser.

In the current context, JavaScript / CSS / HTML related standards in various fields of the web are mature, and browser cores tend to be unified. The core focus of front-end engineering has gradually shifted to research and development to improve efficiency. Bundleless mode can bring long-term startup and HMR speed, which is a major development trend in the future. With the constant unification of browser kernel and web standards, it is possible for the front-end code to run directly without packaging, which will further improve the overall R & D efficiency.

Finally, I would like to thank esmodule, vite, snowpack and other standards and tools for taking a big step forward in the front-end development experience.

Recommended Today

Modal dialog plug-in based on native JS encapsulation

Encapsulating modal dialog plug-in based on native JS Native JS encapsulates the modal dialog plug-in, which is used by individuals to learn principles and ideas. There is only a simple implementation of the basic framework, and more configuration items can be added on this basis API configuration //Basic grammar let modal = ModalPlugin({ //Prompt title […]