An overview of the

Speaking of script tag, I believe it must be familiar to us front-end development engineers. On the contrary, it may also be very familiar. After all, it is a tag that we use very frequently. Let’s talk about its Type property

type

The value of the type attribute is the MIME type, which stands for Multipurpose Internet Mail Extensions Type. Most of the time, the server tells the client (browser) what the media Type is through the HTTP protocol. In fact, the server tells the browser what the media Type of the response body is through the content-Type header. This media Type determines exactly how the Content returned by the server (the response body) should be handled by our browser, such as a common content-type:

Content-Type: text/html;
Copy the code

The browser will parse the response as if it were an HTML file

text/javascript

When it comes to the type attribute value of the script tag, I believe most of us are most familiar with text/javascript. However, we may not be able to type these words manually. After all, the editor we use when we type in script, The emmet plugin will automatically prompt us to hit TAB and it will complete the script for us:

<script></script>
Copy the code

Many years ago when I was writing code, THE editor I used was Sublime Text. I can’t remember if the autocomplete script tag used the Type attribute, but vs Code doesn’t use it now, but I do use it manually every time:

type="text/javascript"
Copy the code

So the end result is:

<script type="text/javascript"></script>
Copy the code

Of course, ellipsis is also possible, after all, probably most people are ellipsis, but I started to learn front-end, js when I saw the script tag has type=”text/javascript”, so this habit is still used today

Also, if we omit this property, the default value will also be text/javascript, which is taken from the Little Red Book: javascript Advanced Programming (3rd Edition) :

For convention and maximum browser compatibility, the current value of the type attribute is text/javascript, but this attribute is not required, and if it is not specified, the default value is text/javascript

So, there are two ways to express ascript whose type is text/javascript:

  1. omittypeProperties:
<script></script>
Copy the code
  1. Write the wholetypeAttribute valuestext/javascript:
<script type="text/javascript"></script>
Copy the code

My personal habit is to write the complete type attribute value text/javascript, the specific writing method can be based on personal preference, do not adhere to a certain type

The value of type is text/javascript. In this case, the browser will execute the contents as javascript. Therefore, the code we write inside must conform to the SYNTAX of JS, otherwise it will report an error

In addition to text/javascript, there is another common type value written in script that I think most people, like me, first see when they right-click > view the source code of the web page. It is application/json

application/json

When we look at this type value, we might think of a response header in the server when our classmate returns data to us:

Content-Type: application/json;
Copy the code

allows the browser to execute the contents of the tag as js. That is:

<script type="application/json"></script>
Copy the code

What does the browser do with the content? Do you treat it as JSON? We can try it:

  <script type="text/javascript">
    const num = 123;
    console.log(num);
  </script>
Copy the code

When the browser opens the HTML and opens the console, we can see that 123 is output. Ok, as expected.

  <script type="application/json">
    const num = 123;
    console.log(num);
  </script>
Copy the code

At this time, we refresh the page and open the console again to check, we find that 123 is not output, the console is blank, there is no error and no output content, and when we think carefully, this is because when the type attribute of script is text/javascript, The contents of a script are executed as js by the browser, so the initial JS is executed and the output is 123. If the type of a script is application/json, the browser will not execute the contents of a script as JS. What if we change the contents of the script tag to JSON:

  <script type="application/json">
    {
      "data": [
        {
          "a": 1,
          "b": 2
        },
        {
          "c": 3,
          "d": 4
        }
      ],
      "total": 100
    }
  </script>
Copy the code

If I open the console and nothing changes, what if I want to get what’s in there? If the content of a tag is a string and the content of this tag is a string that complies with JSON syntax, can we convert it to JSON?

Give it a try

To make it easier to get the contents of this script[type=”application/json”], we give it an id:

  <script id="json-script" type="application/json">
    {
      "data": [
        {
          "a": 1,
          "b": 2
        },
        {
          "c": 3,
          "d": 4
        }
      ],
      "total": 100
    }
  </script>
Copy the code

Then fetch the contents of the tag with a section of JS and convert it to JSON:

  <script type="text/javascript">
    const node = document.getElementById('json-script');
    const jsonStr = node.innerText;
    const json = JSON.parse(jsonStr);
    console.log(json);
  </script>
Copy the code

At this point we refresh the page again and open the console and see json output:

What if you write something that doesn’t conform to json syntax, or intentionally breaks json syntax? For example, breaking the syntax of JSON and then not fetching or parsing it:

< script id = "json - script" type = "application/json" > {" data ": [{" a" : 1, "b" : 2} / / it deletes the comma {3, "c" : "d" : 4 } ], "total": 100 } </script>Copy the code

This is fine, but if we fetch and parse, we get an error:

Uncaught SyntaxError: Unexpected token / in JSON at position

Of course, this is the explanation that I added here, it’s a comment, I deleted the comment:

  <script id="json-script" type="application/json">
    {
      "data": [
        {
          "a": 1,
          "b": 2
        }
        {
          "c": 3,
          "d": 4
        }
      ],
      "total": 100
    }
  </script>
Copy the code

Uncaught SyntaxError: Unexpected Token {in JSON at position

The JSON syntax is broken

If the script tag type is application/json, the browser will not parse the content as js, because it will not execute when we write js code in it, and when we write json content in it, We can take that content and convert it to JSON, but we can’t convert it to JSON if it doesn’t fit the JSON syntax

Look at the MDN article script and we find the answer:

If the MIME type is not a JavaScript type (supported above), the content contained in the element will be treated as a block of data and will not be executed by the browser.

That is, when script type is application/json, the browser will treat the content as a block of data, not as js, which is json

Why is it in the source code of the page

The first time I saw the type value of this script was in the source code of the web page. Specifically, I saw it in the React app called SSR, Server Side Render developed by NextJS. Let’s look at a couple of examples

720yun

Open 720yun, right click > view the source code of the page, and search for Application /json. Then we can see the script tag with type application/json.

<script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"isMobile":false,"coverpano":[{"product":{"xml":"\u003c?xml version...
Copy the code

720 yun BBS

Open a 720yun forum with script[type=”application/json”] and the structure of the content is the same as 720yun

Both of these websites are renderers of react apps using nextJS. We can see that there is a script tag on the page with id __NEXT_DATA__ and type value application/json, which contains the data required for the page. You can also view some configuration information for the site through window.__next_data__, which is a global context for nextJS framework Settings

Here we look at a SSR website, nine machine network

Nine machine network

In the same operation, we open jiuji.com and right click > check the source code of the page. At this time, we search the content of the page, search application/json, and find that there is no script[type=”application/json”] in it, but the website is still SSR. This indicates that the script[type=”application/json”] tag in SSR projects is not required

summary

The reason why I saw script[type=”application/json”] in the page is that I am also using this framework. Therefore, my curiosity and curiosity drive me to make some further explorations, hence this article. However, I later found that script[type=”application/json”] was not the standard CONFIGURATION of SSR, but after using Nextjs, it would create such a label, and then put the data of the page in it. As for the reason, I also made some searches myself, you can see this issue for details: Why does __NEXT_DATA__ exists? In which a NextJS developer gave us the answer:

  • Inside the server, it pre-render HTML
  • Then inside the client, React need to map this HTML with the components related to this page
  • Otherwise, there’ll be a flash in the screen, which looks ugly
  • So, it need to generate the same HTML inside the client.
  • If those two are the same, React is happy and continue the client side work

Translation:

  • Inside the server, it prerenders HTML
  • Then on the client side, React needs to map the HTML to the components associated with the page
  • Otherwise, there will be a flicker on the screen and it will look ugly
  • Therefore, it needs to generate the same HTML on the client side
  • If the two are the same, React will be happy and continue working on the client side

In a nutshell: This is a pre-rendering on the server side, and then the client side (browser) needs to use this data to map relevant components of the page. In addition, I think that when our Web App runs on the browser side and then switches pages, this data can also be used for the purpose of Web App. Of course, Except when a page switch requires a request for new data

Application scenarios

So, let’s talk about the application/ JSON usage scenario I came across

SSR project additional data processing

Recently, I made a project of NextJS + GraphQL react app and SSR. After obtaining the data rendering page, the page rendering effect was consistent with the expected, consistent with the design draft, and the interaction was reasonable and smooth. Then the life cycle of a project basically came to an end, but some special data was encountered at this time:

  1. Outside of the business architecture originally designed
  2. It is not convenient for the server to add fields to the existing table
  3. It is not convenient to add a field to the return of the front end. If it is added, the process will be very complicated, because the logic of the architecture level is complicated and multi-layer structure, so the processing of the extended field needs to modify the relevant logic of the data flow, which is not worth the loss

So the server puts the data into a field that already exists, presumably to ascript [type=”text/javascript”] that looks something like this:

  <script type="text/javascript">
    const xxxData = [
      {
        a: 1,
        b: 2
      },
      {
        c: 3,
        d: 4
      }
    ]
  </script>
Copy the code

Of course, the actual code is compressed, so this is just for viewing purposes

After the data is given, I use regular expression in my SSR service to obtain the data, and then use it. This way can meet the requirements, but there are several problems:

  1. To the server this is just a meaningless string, but to the client (browser) it is a stringjsCode, not data
  2. Because it’s a paragraph to the browserjsCode, so the browser will execute it

The server gives me data, and my browser should also treat it as data, not as JS to execute, so finally use application/ JSON processing:

  <script id="xxxData" type="application/json">
    [
      {
        a: 1,
        b: 2
      },
      {
        c: 3,
        d: 4
      }
    ]
  </script>
Copy the code

I also used the regular expression in my SSR service to obtain the data, because the data was added to an existing field, so we also need to consider the existing field does not have this data, the final code is as follows:

/ / returns the script of matching the back-end json string const handleMatchJsonStrInScript = STR = > {the if (! str) { return null; } const scriptRegExp = /<script.*id="xxxData".*>(.*)<\/script>/; const matchResArr = str.match(scriptRegExp); if(! matchResArr) { return null; } // json string in script const jsonStr = matchResArr[1]; Parse (jsonStr); // Convert string to json obj const jsonObj = json.parse (jsonStr); return jsonObj; };Copy the code

The result is a piece of JSON data:

[
  {
    a: 1,
    b: 2
  },
  {
    c: 3,
    d: 4
  }
]
Copy the code

This gives us the data we need, but the browser doesn’t have to parse and execute the data because it’s not a piece of JS code

A static page item that displays fixed data

For example, some toG projects, such as school introduction or school directory projects, school data is provided by the school or other relevant partners, such data is usually word document or Excel, and these fixed data are displayed on our page. In addition to creating a JS file to load the data, you can also write the data to the HTML page:

< script id = "json - script" type = "application/json" > {" data ": [{" name" : "a primary school", "desc" : "aaaaa"}, {" name ": "B primary school", "desc", "BBBBB"}], "total" : 100} < / script >Copy the code

Then we get it through JS, and the key code is as follows:

  const jsonScriptNode = document.getElementById('json-script');
  const jsonStr = jsonScriptNode.innerText;
  const json = JSON.parse(jsonStr);
Copy the code

In this way, you can avoid redundant network requests when loading data with JS, and the semantics are more clear

module

Module, as the name says, is modular, is our CommonJS, CMD, AMD and all of this stuff, it started out as the community, the front-end guys implementing their own modularity, seaJS, the CommonJS specification that nodeJS uses, and asynchronous module definition AMD, Finally, the official ES6 Module is also the most widely used modular specification in our front-end engineering development

ES6 In Depth: Modules, here is only a discussion of this feature. The specific import export export default will be written In a separate article, which will not be described here

Give a brief summary with a passage from the above article:

An ES6 module is a file containing JS code. There’s no special module keyword; a module mostly reads just like a script. There are two differences.

  • ES6 modules are automatically strict-mode code, even if you don’t write “use strict”; in them.
  • You can use import and export in modules.

An ES6 module is a file containing JS code. There is no special module keyword. A module is usually read just like a script, with two differences:

  • ES6The module is automatically enabledStrict modeEven if you didn’t write it in there"use strict"
  • You can use it insideimportandexport

This gives us a simple definition of the module: we can use the import and export script tags so that we can try the Module scenario

Direct import use

We create a directory with a module. HTML file, /public directory, /public/js/a-module.js

project
|--public
|   |--js
|   |   |--a-module.js
|   |--module.html
Copy the code

module.html:

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta  name="viewport" content="width=device-width, Initial-scale =1.0"> <title> modular </title> </head> <body> <script type="module"> import {funca} from './public/js/a-module.js'; funca(); </script> </body> </html>Copy the code

/public/js/a-module.js:

Export const funca = () => {console.log(' I am a-module'); };Copy the code

When we open our module. HTML file, we find a cross-domain error:

Access to script at 'file:///D:/js/a-module.js' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.

GET file:///D:/js/a-module.js net::ERR_FAILED

This is because script[type=”module”] is restricted by the CORS policy and opens files directly in the browser using the file protocol, only HTTP, data, Chrome, Chrome-extension, chrome-untrusted, If HTTPS is available, we can create a local service and create a server.js file:

project
|--public
|   |--js
|   |   |--a-module.js
|   |--module.html
|--server.js
Copy the code

server.js:

const path = require('path'); const express = require('express'); const app = express(); const DIST_DIR = path.join(__dirname, 'public'); const PORT = 9090; app.use(express.static(DIST_DIR)); App.listen (PORT, function() {console.log(' successfully started: http://localhost:${PORT} '); });Copy the code

Here I use 9090, mainly to prevent port conflicts with other projects, now we start the service:

$ node server.js
Copy the code

Then open this address:

http://localhost:9090/module.html
Copy the code

Now we can use our script[type=”module”] normally, open the console and see that the funca method in a-module.js executes:

I am a - the moduleCopy the code

Module import for use

Create a /public/js/b-module.js file and import our a-module.js file in it:

import { funca } from './a-module.js'; Console. log(' I'm b-module, I execute methods in A-Module :'); funca();Copy the code

The directory structure is as follows:

project
|--public
|   |--js
|   |   |--a-module.js
|   |   |--b-module.js
|   |--module.html
|--server.js
Copy the code

Import b-module.js in our module.html as well:

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta  name="viewport" content="width=device-width, Initial-scale =1.0"> <title> modular </title> </head> <body> <script type="module"> import {funca} from './js/a-module.js'; funca(); </script> <script type="module" src="/js/b-module.js"></script> </body> </html>Copy the code

The console output is as follows:

I'm a-Module I'm B-Module, AND I execute the methods in A-Module: I'm A-ModuleCopy the code

In line with expectations

To try the ES6 class again, we create a c-module.js:

Class C {name = 'c-module' selfIntro = 'I am a class' sayHello() {console.log(' my name is ${this.name}, ${this.selfintro}'); } } export default C;Copy the code

Create a new d-module.js file and import c-module.js and instantiate it:

import C from './c-module.js'; Console. log(' I'm D-Module, I'm going to execute code in C-Module :'); const instance = new C(); instance.sayHello();Copy the code

At this point our directory structure is as follows:

project
|--public
|   |--js
|   |   |--a-module.js
|   |   |--b-module.js
|   |   |--c-module.js
|   |   |--d-module.js
|   |--module.html
|--server.js
Copy the code

Modify HTML file:

<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta  name="viewport" content="width=device-width, Initial-scale =1.0"> <title> modular </title> </head> <body> <script type="module"> import {funca} from './js/a-module.js'; funca(); </script> <script type="module" src="/js/b-module.js"></script> <script type="module" src="/js/d-module.js"></script> </body> </html>Copy the code

Console output after page refresh:

I'm a-Module I'm B-Module, I execute the methods in A-Module: I'm A-Module I'm D-Module, I execute the code in C-Module: My name is C-Module, I'm a classCopy the code

Script [type=”module”] can I use module? Secondly, engineering allows us to develop in the way of modules or components, while WebPack processes them into IIFE form codes. Meanwhile, Babel transforms our ES6 ES6+ codes into more compatible ES5 codes, which not only improves our programming experience, but also takes into account compatibility problems

We usually use text/javascript and application/json. Module just makes a record after seeing it

If you find this article useful to you, please give me a thumbs up, click a favorite, and hope there is no code too hard to write, no requirements too hard to implement

Reference article:

  1. script
  2. The MIME type
  3. ES6 In Depth: Modules