The opening
Masturbating at home over the weekend… A [random questioner], A very simple small tool, the requirement is to randomly select A few questions from A bunch of questions for QA (not that I do not believe in the knowledge of digging friends, mainly do not want to create ambiguity, here to explain: Q: namely Question, A: namely Answer, Question, Answer).
When you see this, you probably have the code written in your head.
Don’t worry, we’re not done yet!
I have my own front-end interview question bank, which divides the questions into different categories and then records the questions in the form of Markdown text. So I need to separate these questions and answers from the Markdown. What can I do?
- Copy and paste the answer to the question into a JS object.
- I can’t think of the second point.
I am such a lazy person, almost used the first method, but think of every time in this question bank new topic, I have to corresponding [copy and paste] into the JS object I feel ashamed of this front-end work. At this moment, two corporate spirits of the company — [science] and [innovation] suddenly came into my mind. Yes, this inspired me and I decided to solve this problem by means of code. My thinking is roughly as follows:
- Read the Markdown file to get the text string
- using
unified
Package and associated parsers convert strings toAST - Simplify the AST to the QA object I need
The difficulty has been overcome, the idea behind is nothing more than to create random numbers,…. I won’t go into further details.
What can you learn from reading this article?
- Practical usage scenarios for WebPack and some new features
- Know and apply
unified
Toolkits and associated parsers - How do I read the contents of files in a project
- Strengthen your understanding of AST
- You can write your own gadget
- .
Please ignore this section (big) in the usual life, I believe that everyone in mind could be seen all kinds of effect of small tools, can be put forward at first thought is very good, specific to deep thinking could be found some problems in the existing technology to temporarily don’t know how to do it, because most of the front-end developer’s job is to write business requirements, Therefore, the knowledge is locked in the application level of a few front-end frameworks, so I would like to give some advice to some friends:
I hope you don’t focus all your energy on the frame, jump out of the frame and look at the “outside world”, for example, write a scaffold yourself, try some gadgets yourself, go to Github to see what other people have done interesting things, etc. Never have high ambitions and low hands. A dwarf of action will always go far than a giant of “thought”. Only when you actually do it will you find out if you have achieved anything.
Rotation old face recommended previous articles 🙃 :
- Teach you how to build Vue3 enterprise development environment
- Vue3 source code analysis to achieve a simple version of Vue3
- “Scaffolding CLI” technology revealed
- Information about Flutter that you may not know will be updated continuously…
The body of the
Initialize the project
These packages are the product of modular programming. The early front-end basically uses THE CDN to mount JS files directly to HTML. After loading, the object we need will be mounted to the Window, so we can directly access in the global scope.
Since they are modular products, we need to introduce them in a modular way. This is inseparable from the module packaging tool, the author chose webpack.
First, we initialize the project NPM init at the root of the project.
Install webpack
npm install webpack webpack-cli --save-dev
Copy the code
configurationwebpack
It’s easy to get started with WebPack, but keep the following five points in mind when developing basic (and generally required) configurations:
- Configure the module packaging entry
- Configure module package exit
- Set the template
HTML
, using plug-ins to automatically introduce packaged files into the template - Encounter different modules with different configurations
loader
parsing - configuration
dev-server
And enable hot updates.
This is a basic template, and then you basically tinker with the basic configuration based on your needs.
To create the webpack.config.js configuration file in the project root directory, let’s first configure the entry and exit:
// webpack.config.js
const path = require('path');
module.exports = {
entry: './main.js'.output: {
filename: '[name].js'.path: path.resolve(__dirname, 'dist'),}}Copy the code
Then create a template HTML file under dist folder and install html-webpack-plugin and webpack-dev-server:
npm install html-webpack-plugin webpack-dev-server --save-dev
Copy the code
Perfect configuration:
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './main.js'.output: {
filename: '[name].main.js'.path: path.resolve(__dirname, 'dist')},devServer: {
static: false.compress: true.port: 9000,},plugins: [
new HtmlWebpackPlugin({
template: './dist/index.html'}})]Copy the code
Starting with webpack-dev-server V4.0.0, hot module replacement is enabled by default, otherwise you need to set hot to true in devServer.
Then we modify the script setup startup command in package.json:
// package.json."scripts": {
"test": "echo \"Error: no test specified\" && exit 1"."start": "webpack-dev-server"."build": "webpack"
},
Copy the code
Now that our basic configuration is complete, we can test it by writing a line of code in main.js.
readmarkdown
The file content
There are usually two ways:
- Use direct file import as a string.
- use
fetch
Request the corresponding file path.
For static resource processing, use loader to process file resources before Webpackage 5.0. Webpackage 5.0 has been updated, and loader is no longer needed. Let’s take a look one by one:
Old method (WebPack4.x)
There are usually two ways:
file-loader
Sends the file to the specified pathraw-loader
Import the file as a string
file-loader
Installation:
npm install file-loader --save-dev
Copy the code
To complete the configuration:
// webpack.config.js
module.exports = {
...
module: {
rules: [{loader: require.resolve('file-loader'),
exclude: [/\.(js)$/./\.html$/./\.json$/].options: {
name: 'static/[name].[ext]',},}],},}Copy the code
When WebPack encounters such files, it resolves their paths and sends them to the static/ path.
To fetch a resource file, we need to import the resource file:
import path from './books/demo.md'
/ / or
// Books /demo.md is a 'Module' object:
const path = require('./books/demo.md').default
function fetchFiles(){
fetch(path).then(res= >{
console.log(res); })}Copy the code
raw-loader
It’s easier to import the file as a string:
import demoText from './books/demo.md'
console.log(demoText);
Copy the code
As shown in figure:
Let’s look at new ways to read text content.
New version method
In fact, the way to read files has not changed, but WebPack 5.0 provides a new module type to replace loader, we no longer need to use loader, just need to make some configuration changes.
asset/resource
Send a separate file and export the URL. Previously by usingfile-loader
The implementation.asset/source
Export the source code of the resource. Previously by usingraw-loader
The implementation.
Do the following:
// webpack.config.js
module.exports = {
...
module: {
rules: [{test: /\.md$/,
type: 'asset/resource' / / or asset/source}],}.}Copy the code
At the same time, if we have a path requirement for the resource file, we can also add the configuration:
// webpack.config.js
module.exports = {
...
ouput:{
...
path: path.resolve(__dirname, 'dist'),
assetModuleFilename:'books/[hash][ext][query]' // Static resource path}},Copy the code
Text toAST
The AST is an abstract syntax tree that describes your content abstractly through the data type object:
For example: “There are five people on the bus”
{
transportType: "公交车".// Vehicle type
peopleNumber: 5 / / the number of
}
Copy the code
There are a lot of AST applications, such as Babel, ESLint, Webpack, cross-platform frameworks, etc. There are many partners who know this thing but are unfamiliar with it. They know what it is, and it is difficult to understand its true function. How do we convert ES6 code to ES5 code? How do we convert steel into all kinds of steel products?
We’re not palala fairies. We don’t have the magic to turn steel into steel. We have to smelt the steel first, and then make it into products.
The same goes for javascript. All it can do is manipulate various types of data. Convert ES6 code to an AST, then do something with the AST, convert it to ES5, and write it as a JS file.
Getting back to the subject, let’s convert the markddown text string into an AST. Let’s start with a few toolkits:
unified
: an interface that processes text into an abstract syntax tree, supporting processingremark
(markdown),retext
(Natural language) andrehype
(html).Portal 🚪remark-parse
: one used forunified
Package resolver, willmarkdown
Converted toASTThe syntax tree.remark-gfm
: one for extensionGithubOn themarkdown
Some new syntax parsing plug-ins.
Installation:
npm install unified remark-parese remark-gfm --save-dev
Copy the code
To use:
import { unified } from "unified";
import remarkParse from 'remark-parse'
import remarkGfm from 'remark-gfm'
/** * converts the text string to AST *@param { string } Text needs to be processed as the AST text character */
function handleTextToAST(text){
const processor = unified().use(remarkParse).use([remarkGfm]);
const tree = processor.runSync(processor.parse(text));
console.log('tree',tree);
}
Copy the code
The structure of the transformation tree looks like this:
/ / AST structure
{
type:'root'./ / type
position: {},/ / position
children: [/ / child nodes
{
type:'heading'./ / titlePosition: {},depth:1.children:[
{
type:'text'.value:'React Hooks'.position:{}}]}, {type:'paragraph'./ / paragraphsPosition: {},depth:1.children:[
{
type:'text'.value:'xxxxxxxxxx'.position:{}}]}Copy the code
willAST
Processing intoQA
object
The data structure I want is as follows:
{
q: 'React Hooks'.a: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
}
Copy the code
I’m going to iterate through the AST, identifying the nodes whose type is heading as the question and the nodes whose type is Paragraph as the answer to the previous heading question. There are also some other types of type to consider, such as list, listItem, etc.
/** * simplify AST-> to Object *@param {object} ast
* @returns * /
function handleASTToJSON(ast){
const questions = [] // List of problems
let question = {} // Single problem
if(ast&&ast.children){
ast.children.forEach(element= > {
if(element.type === 'heading') {// push the previous problem onto the stack
questions.push(question)
// Reset the problem
question = {};
getTextInTree(element,question,'q')}else{
getTextInTree(element,question,'a')}}); questions.push(question) }return questions;
}
Copy the code
The questions and answers we need are deeply nested in the tree, so we need to get them recursively to implement getTextInTree.
const TRAVERSE_TYPES = ['heading'.'paragraph'.'link'.'list'.'listItem'.'strong']
/ * * * *@param { object } Obj AST Source object *@param { object } Question Object *@param { string } qaType 'q' || 'a'
* @returns * /
function getTextInTree(obj,question,qaType){
if(! obj)return;
if(TRAVERSE_TYPES.includes(obj.type)){
obj.children.forEach(item= >{
getTextInTree(item,question,qaType)
})
}else{
question[qaType] = (question[qaType] || ' ') + obj.value + "<br /><br />"; }}Copy the code
The resulting data structure looks something like this:
[{q:Â "Throttle
".a: "xxxxxxxxx"
},
{
q:Â "
".a: "xxxxxxxxxxx"
},
{
q:Â "0.1 + 0.2! = = 0.3 < br / > < br / >".a: "xxxxxxx"}]Copy the code
The rest is simple.
Create a random number, read the topic.
To the end:
1. Why make this gadget?
Over the weekend, I received an invitation for an interview and realized that I had forgotten all the interview knowledge I had studied for months before. The answer is repetition, and there’s a scientific basis for it. Of course, there is no denying that putting knowledge into a system in your mind helps you remember. In addition, there are some things that you can recite backwards even though they are not even remotely connected to what you already have in mind, such as Tang Dynasty poems. So, repetition is a very efficient thing to do, and if you use this tool properly to QA yourself, it will save you time preparing for your next interview.
2. Why use the markdown form?
That way I can read it like an ebook on Github while riding the subway or whatever, but there it is, and you can use it in whatever form you want.
Well, other nothing, class 👻!
Friends, learning without thought is useless; thought without learning is perilous. Come on.
I hope I can bring you some harvest.
If the wrong place welcome everyone comment correct, thank you.