Author: Zheng Chengzhong

This article is produced by a member of YFE, please respect the original, please contact the public account (ID: yuewen_YFE) for authorization to reprint, and indicate the author, source and link.

When you think of componentization, I’m sure most of you will think of React, Vue, Angular… This is the front end framework.

But there’s always a question in my mind, is it these frameworks that make componentization possible? Or does componentization make these frameworks work?

directory

  1. Why componentize
  2. Why not use a frame
  3. The theoretical basis of frameless componentization
  4. No frame componentization actual combat experience

The total number of words in the article is 4000+, and the article is long and dry in the last section

Why componentize

We all know that HTML, CSS and JS correspond to the structure, style and behavior of a web page.

Componentization reduces focus

Suppose you now have a function: a red button that you click to print the text on the alert-text property.

Implemented in its original form, it must be used with the understanding that:

  1. CSS File Path./component/button.css
  2. Js file path./component/button.js
  3. Two CSS selectorsbtn.j_btn_alert(and their naming rules)
  4. Tag namebutton
  5. Button typetype="button"
  6. Copywriting attribute nameData-alert-text =" You clicked on me"
  7. Button to copyclick

React componentization logic (here, React) looks something like this:

  1. Component file path./Button/index.js
  2. Component nameButton
  3. Copywriting attribute nameAlertText =" You clicked on me"
  4. Button to copyclick

It is clear that from the user’s point of view, componentization is much less concerned than the original solution.

The original link

HTML JS CSS checks and balances

In my opinion, writing a web page is a lot like building a house. Each page corresponds to each room, and each element in the room corresponds to a different module. The traditional architecture and logic of websites are similar.

HTML, CSS, and JS are related to each other through file references and selectors, if we want to move the table from room A to room B. Not only to move the table HTML, JS, CSS. We need to know what’s on the table.

For example, if you have a lamp on your desk, you also have to move the HTML, JS, and CSS of the lamp to room B.

And there may be other objects on the table, all of these logical relations, have to be found manually, for the students who are used to compontized development, it is a nightmare.

Components are related to each other through interfaces from a componentization perspective.

When reusing a component, it is all about the internal logic. You don’t even have to be aware of HTML, JS, and CSS themselves. Everything is a component in the eyes, the user only needs to do the porter of the component, as well as the docking interface.

Componentization saves money

To know, the porter this matter, is not too much technical content. The previous project may need to recruit 4 senior engineers (must be familiar with the structure and specifications of the whole station). With componentization, it might only take 2 senior engineers to write the components and 2 junior engineers to move them. Later, when the component library is complete, senior engineers only need to work part-time as technical consultants on the project.

Component reuse can further save manpower if multiple projects share the same technical architecture.

Of course, in real projects it’s not nearly as simple as this. This is just based on the idea that componentization can make it easier to achieve high cohesion and low coupling in the code. In theory, componentization can save manpower. After all, how components are packaged is a big science.

Why not use a frame

Before we explain why, let’s hear a ghost story about you crossing the river to find your girlfriend.

One day, you and your girlfriend make a weekend appointment to go to the river to watch the stars, only to find that there is no bridge.

However, you don’t go together, you just meet at the river, which just happens to divide you and your girlfriend.

Your girlfriend wants you to cross the river to find her, and if you don’t, she’ll break up with you.

In this moment of extreme anxiety, you tell yourself not to panic, the whole situation you have to hold. So you look carefully around the river.

  1. Beside the river there was a tree with a rope to swing across;
  2. There are several boards beside the river, which can be made into a large board to cross the river on the bridge;
  3. Maybe you’re a carpenter yourself, and you just use these parts to build what could simply be called a bridge;
  4. There are several bridge building factories near the river. If you get the parts, you can directly assemble a complete bridge according to the instructions.

Is this a ghost story?

If you think of the girlfriend as a product manager, think of crossing the river as a project requirement. Does this all sound like an everyday ghost story?

The product manager may require not only you, but your entire team to cross the river, and may give you half a day. If not, your team is not skilled enough.

This is all about drama, and I love you guys.

Back to the project problem, the above four states actually correspond to the four ways to solve the problem:

  1. Primitive: whatever it is, first complete the needs of the past, but not every partner in the team can cross the river by rope;
  2. Modularization: Temporary build some simple modules, can solve the problem. But as a user, you need to fully understand the rules of module assembly and how to use them;
  3. Componentization: encapsulates a complete component, for the user, just need to know, where the bridge comes from, how to use the bridge;
  4. Frame: it can make a small partner with no professional ability to build a bridge across the river according to the instructions;

Frames cost

What does the framework bring? This article

Need to choose: one is called React and the other is called Vue.

Learning cost: Everyone on the team had no experience with React and Vue before, so they had to learn from zero.

Uncertainty: Factories can be replaced at any time. One factory may be popular today, another (Nokia) the next;

Exclusivity: It is difficult to use two factory design concepts (Apple and Android) in the same project.

Full acceptance: Acceptance of a factory’s disadvantages as well as its benefits;

Of course, if your team is all Facebook employees, using the React framework should be a quick and good choice

Frameless componentization

In the actual project development process, we can not use the framework, often not the framework is not good enough, but the project is a big helpless move. Just because I want to use the React framework doesn’t mean I have to stop the project completely to upgrade the framework.

I want to componentize, but I can’t use frame, what do I do?

At this point, you need to analyze what the framework is doing at the componentization level.

build

In traditional file-based builds, files of the same type are placed in a single folder for easy processing, but this requires manual reference relationships.

Componentization takes a JS file as the entry file for the component. And use this entry file to organize internal dependencies.

Components are written cohesive, but when the user sees the page, they are actually ripped apart, laid out in HTML, and linked with various “hooks” through file references. The dependency analysis requirements for this build can be very high.

The easiest solution to do this is Webpack, which also uses Gulp for dependency analysis

HTML First 🆚 JS First

React and VUE both use JS as a starting point to describe a component and its internal relationships. HTML is good at describing structure, CSS is good at describing style, dependencies and logical relationships, and JS is obviously better.

JS is preferred, which also makes it easier for build tools to do dependency analysis. With the popularity of frameworks, you’ll hear things like CSS in JS, JSX(HTML in JS)… So the JS-first scheme is killed.

The traditional approach is htML-first. Usually we use an HTML template engine to describe the structure of a component. When data is available, use the template engine’s Render method to retrieve the rendered HTML.

<! -- home.ejs -->
<html>
  <body>
    <h1><%= data.title %></h1>
    <p><%= data.description %></p>
  </body>
</html>
Copy the code
/** home.js **/
import ejsHome from "./home.ejs";
import EJS from "ejs";
const data={
  title:'home'.description:'This is the home page'
};
const html = EJS.render(ejsHome, {data});
return html;
Copy the code
<! -- home.html -->
<html>
  <body>
    <h1>Home page</h1>
    <p>This is the home page</p>
  </body>
</html>
Copy the code

This is where the HTML first scheme comes in. Because HTML can’t do everything, even if HTML takes precedence, template engines are still needed. JS is still needed to concatenate HTML templates and data.

Therefore, in order to make componentization, JS First is currently recommended.

Isomorphism of actual combat

The previous sections covered the benefits of componentization, some of the costs of choosing a framework to promote componentization, and two theoretical foundations for wanting to implement frameless componentization (build enablement, JS First).

This section about the actual combat, to our Webnovel (need science online) as an example, to introduce

  1. PC site (traditional jQuery project) : www.webnovel.com
  2. M station (React framework) : m.wenovel.com

These two sites represent, respectively, the traditionalists and the framers mentioned earlier.

Interestingly, the development experience of the PC site was worse than that of the M site. However, in terms of page loading speed, SEO and page performance, PC site is obviously better than M site.

In order not to pick a quarrel, lose a quarrel. We chose to try frameless componentization between tradition and framework. In our opinion, if you can componentize on the PC site, it will greatly improve the development experience.

Upgrade to build

When we upgrade our build from Gulp to Webpack, the most intuitive physicality from a development perspective is that our file structure becomes free.

Of course, this does not only mean that we can componentize our folders, but also that the componentized folders can be compatible with the original file structure. Because the build itself doesn’t care what the folder structure is, it doesn’t matter as long as the path dependencies are correct.

In other words, we can gradually enhance the componentization of the site. Old modules and pages, just sit there and let the years pass. New page, new function, componentized development happy.

JS First

CSS and index.ejs files can be referenced directly with the index.js entry file after the build upgrade. The user simply references index.js and initializes it.

Isn’t that close to the componentization mentioned earlier?

The concept of JS First, which was mentioned earlier, simply means that HTML in JS makes components more cohesive. In this example, you can even replace the original EJS HTML template engine with a JS string template.

However, when we formally describe the structure itself in this unstructured (functional) way in the project, it seems very difficult.

React can describe the relationships between components in a structured way (similar to HTML), which perfectly solves this pain point.

However, when we talk about frameless componentization, do we use React again? No! We don’t want to!

JSX without React

Introduces the new JSX transformation, jump link

Here’s the React website. JSX no longer relies on React, but is built into the new version of Babel.

Add @babel/plugin-transfrom-react-jsx to the Babel configuration to convert JSX into Function syntax. Wait a minute! The Function of grammar? Function is HTML.

At this point JSX to HTML became our new problem.

However, the solutions we can find are all runtime, and they create elements using the document.createElement(tagName) browser API. The transformation we want is at component time. We had no choice but to build our own wheels.

Jsx2string: Click me to view the NPM package

JSX uses the structured syntax of JSX in React. It has nothing to do with React and cannot use all the logic in React except the template.

Just to go through the process, it’s actually pretty simple. If you write JSX syntax in JS, Babel will convert it to Function at build time, and then use jSX2String to get the HTML string you want.

Server side rendering

Up to this point, the logic rendered on the non-server side can already be componentized.

But our current server rendering for PC stations is koA + EJS logic. Again, the familiar smell of HTML First.

It used to be using EJS to piece together HTML templates and data to get the HTML rendered. Now that we’ve implemented JS First, we just need to pass the data as an argument to the Render method to get the HTML.

Because the server render JS file, just need to get the server data, execute spit HTML string. It’s not exactly what browser-side JS does.

In local development, there are actually two builds, one is to build the index.js file required by the browser, and one is to build the index.node.js server.

.└ ─ Home ├─ index.txt // ├─ index.txt // index.txt //Copy the code

Now, there’s a difficult point, In index.node.js, you need to take all the dependencies in index.js and put them in the link and script tags (webpack builds a page with multiple JS and CSS dependencies) and run them in the browser.

And the index.node.js file itself has dependencies. To reduce complexity, we pack all the index.node.js dependencies into a single file.

So we only need to deal with the dependency injection of index.js. Here we are using a Hack.

We all know that the webpack plugin htMl-webpack-plugin can generate HTML files based on the template and automatically put all the dependencies in the chunks.

new HtmlWebpackPlugin({
  filename: "./home/index.config.js".chunks: [ "Home/index"].// This contains all dependencies in the home/index.js file
  htmlPluginOption:({ htmlWebpackPlugin }) = >`module.exports = The ${JSON.stringify(htmlWebpackPlugin)}; `
});
Copy the code

Since we don’t need HTML, we let the HTml-webpack-plugin return an index.config.js file that contains all the current dependencies.

.└ ─ Home ├─ index.config.js // Index.js // Index.js // index.js // index.js // ├ ─ └─ index.node.js // server rendering js fileCopy the code

So we will start building the index.js file, then analyze all dependencies, and output the configuration file index.config.js that contains the dependencies. The index.nodex.js build is packaged as an executable single JS file for final server rendering.

When rendering on the server, inject the object returned by the index.config.js configuration file, along with the data requested by the server, into the index.nodex.js rendering method, and then execute the output HTML.

Although this has achieved the effect we want, but always feel a little ugly, I wonder if friends have better suggestions.

conclusion

Here we will be our PC whole station of componentization to advance a big step. It is worth noting that this componentization comes at no additional cost to the framework.

Because I landed in the final project componentization promotion. So I’ve avoided the question of componentization itself. For example, componentized encapsulation, as mentioned earlier, is itself a complex science. Too much cohesion is often not flexible, too flexible users need to focus on more points. There is a balance to be struck based on team capabilities.

There is no absolutely good plan, absolutely bad plan, everything depends on whether it is suitable.