“This is my fourth day of participating in the First Challenge 2022. For more details: First Challenge 2022.”

Environment configuration

Build with Webpack and webpack-dev-server

Reason to use WebPack: It’s easy to debug applications in real time in a browser (rather than a NodeJS environment), and the browser console is much better than the White text console on a black background.

Create “ID” file

npm init
Copy the code

Install webpack, webpack-cli, webpack-dev-server

I installed the latest version of webpack, webpack-cli, webpack-dev-server, here I actually dug a hole for myself.

Write the configuration file webpack.config.js

I confidently wrote the configuration file following the tutorial as follows:

const path = require("path"); module.exports = { mode: "development", entry: "./src/index.js", output: { filename: }, // dev-server devServer: {contentBash: path.join(__dirname, "WWW "), compress: false, port: 8080, publicPath: "/xuni/", } }Copy the code

Before I get to the problems I encountered, let me explain what each configuration sentence means: mode: development mode; Entry: indicates the entry file. Filename: indicates a virtual package file. ContentBash: static file root directory; Compress: indicates that no compression is performed. Port: indicates the port number. PublicPath: indicates the virtual packaging path

Write the entry file index.js

Customize.

Write the static file index.html

Note here, be sure to import your JS files, but! Not index.js, but your own export (virtual packaging) file. Reason: the virtual packaged file can realize the change entry file index.js is saved at the same time, the browser automatically updated.

HTML </h1> <script SRC ="/xuni/bundle.js"></script>Copy the code

run

Before running, remember to change the debug name in package.json

"scripts": {
    "dev": "webpack-dev-server"
  }
Copy the code

After the change, run confidently:

npm run dev
Copy the code

???? I’m confused, why?? Then I thought of a situation where my Webpack version was too new!! The webpack installed by the teacher in the tutorial is 4, so is this likely to cause the configuration version update? I obediently went to check the error, found sure enough! The configuration of webpack5 is different from that of webpack4. Here is the webpack5 configuration file:

const path = require("path"); module.exports = { mode: "development", entry: "./src/index.js", output: { publicPath: "/xuni/", filename: Dev-server devServer: {static: path.join(__dirname, "WWW "), compress: false, port: 8080,}}Copy the code

Conclusion:

In the Webpack5 version, the static file attribute name must be changed to static, and the publicPath virtual package path must be placed at the same level as filename and wrapped in the Output object.

And then!! Run!!!!!

Perfect! Open the url

Handwriting scanner scanner class

What it does: Splits a template string into parts using the “{{” and “}}” characters as separators. (Separate variables)

First, be sure to import the template strings and data we need.

index.html:

<script SRC ="/xuni/bundle.js"></script> <script> var templateStr =" Today {{day}}, weather {{weath}}"; Var data = {day: "day ", weath:" blizzard ",} templateEngine. Render (templateEngine, data); </script>Copy the code

Introduce our scanner class in index.js

index.js:

import Scanner from "./scanner" window.templateEngine = { render(templateStr, data) { var scanner = new Scanner(templateStr); }},Copy the code

We instantiate a scanner and construct it by supplying only one template string, indicating that the scanner only works on template strings (just splitting strings).

Write the class in scanner.js

scanner.js:

Define class scanner:

Scanner export default class Scanner {constructor(templateStr) {this.templateStr = templateStr; // this. Pos = 0; // tail the tail starts with the template string this.tail = templateStr; }}Copy the code

Method scannerUtil() :

Allows the pointer to scan until the specified content is encountered, and returns all text scanned before the end

ScanUtil (stopFlag) {var begin = this.pos; While (this.pos < this.templetastr.length && this.tail.indexof (stopFlag)! == 0) { this.pos++; this.tail = this.templateStr.substring(this.pos); } / / return before all of the contents of the substring (begin and end) var result = this. TemplateStr. Substring (the begin, enclosing pos); return result; }Copy the code

Define method scan() :

Function: The function merely skips the specified content

scan(flag) { if (this.tail.indexOf(flag) == 0) { this.pos += flag.length; this.tail = this.templateStr.substring(this.pos); }}Copy the code

Note here: It is important to remember that tail is also changed, changing the tail from the current pointer character to the last character

Define method EOS () to determine whether the scan needs to end:

Full name End of String Indicates whether to end

eos() {
        return this.pos >= this.templateStr.length;
    }
Copy the code

To reference a method in index.js:

while (! scanner.eos()) { var word = scanner.scanUtil("{{"); console.log(word); scanner.scan("{{"); var word1 = scanner.scanUtil("}}"); console.log(word1); scanner.scan("}}"); }Copy the code

The complete code

index.js:

import Scanner from "./scanner" window.templateEngine = { render(templateStr, data) { var scanner = new Scanner(templateStr); while (! scanner.eos()) { var word = scanner.scanUtil("{{"); console.log(word); scanner.scan("{{"); var word1 = scanner.scanUtil("}}"); console.log(word1); scanner.scan("}}"); }}},Copy the code

scanner.js:

export default class Scanner { constructor(templateStr) { this.templateStr = templateStr; this.pos = 0; this.tail = templateStr; } scan(flag) { if (this.tail.indexOf(flag) == 0) { this.pos += flag.length; this.tail = this.templateStr.substring(this.pos); } } scanUtil(stopFlag) { var begin = this.pos; while (! this.eos() && this.tail.indexOf(stopFlag) ! == 0) { this.pos++; this.tail = this.templateStr.substring(this.pos); } var result = this.templateStr.substring(begin, this.pos); return result; } eos() { return this.pos >= this.templateStr.length; }}Copy the code

Handwriting transforms HTML into tokens

In fact, the idea is very simple, which is to divide the string into an array set, that is, to add a subarray to an empty array.

If you don’t have to loop

templateToTokens.js:

import Scanner from "./scanner" export default function templateToTokens(templateStr) { var tokens = []; var scanner = new Scanner(templateStr); while (! Scanner. Eos ()) {var word = scanner. ScanUtil ("{{"); // Store to array if (word! == "") { tokens.push(["text", word]); } // Skip the double parentheses scanner.scan("{{"); Var word1 = scanner.scanutil ("}}"); tokens.push(["text", word1]); scanner.scan("}}"); } return tokens; }Copy the code

If I have a one-dimensional array that I need to loop through

In addition to “{{” and “}}”, we also need to judge a “#” and “/”, that is, the beginning and end of the traversal symbols. TemplateToTokens. Js:

var word1 = scanner.scanUtil("}}"); if (word1 ! = = "") {/ / the Word here is {{}}, so only need to determine the Word [0] the if (word1 [0] = =" # ") {tokens. Push ([" # ", word1 substring (1) "); } else if (word1[0] == "/") { tokens.push(["/", word1.substring(1)]); } else { tokens.push(["name", word1]); } } scanner.scan("}}");Copy the code

Index. Js:

import templateToTokens from "./templateToTokens" window.templateEngine = { render(templateStr, data) { var tokens = new templateToTokens(templateStr); console.log(tokens); }},Copy the code

The tokens are nested by hand

So far, the code is moving forward, but! When an array has two or more layers nested, the print is not as intuitive or aesthetically pleasing.

The next step is to use some structure to make nested arrays beautiful.

Previous section: The Vue source code for Mustache Template Engine 01