Make prettier format wxss with one click (Part 1)

Time:2021-9-2

This article will combine eslint, prettier, husky, lint stage, gulp.js and other tools to make the project one click operation and reduce the waste of time in formatting, code checking and other operations. Because the large front-end really has too many things to learn. If we don’t learn to be lazy, we will fall behind more.

The sample demo for this series of articles is here, GitHub: wechat_ applet_ demo。

It is divided into three articles:

  • Make prettier format wxss with one click (Part 1)
  • Make prettier format wxss with one click (Part 2)
  • Make prettier format wxss with one click (Finale)

There are also updates here in Jianshu.

Recently, I was working on the front-end project of the company to migrate git from SVN. Because the historical code had not introduced tools such as eslint and prettier code checking or format constraints before.

At present, I am the only one left in the Department to maintain these more than a dozen small programs and H5 front-end projects. Now, as long as you contact the projects you didn’t handle before, you have a headache and don’t want to change. Although the thought is like this, I am helpless. Who makes me just a “wage earner”!

Make complaints about the topic.

1、 Necessary

1. Create a wechat applet project

This is too simple to omit 10000 words

#Or clone wechat_ applet_ Demo project down
$ cd your_folder
$ git clone [email protected]:toFrankie/wechat_applet_demo.git
2. Use yarn as a package management tool

yarnThe related installation is not in this series of tutorials, I believe you all understand. No longer repeat, search by yourself.

3. Use Visual Studio code as the editor

Although I have been engaged in front-end development for some time, I’m sorry. I only use vs Code for front-end development. It should still be used for a long time in the future. As for what webstorm, atom, sublime text, etc. have been used, but they are no longer available.

Anyway, it doesn’t matter what development tools are. Just use them comfortably.

The following describes several vs Code plug-ins related to this project

Eslint: automatically detect the eslint rule. If it does not comply with the rule, there will be a warning on the editing page
Prettier – code formatter: can be used for formatting

After following the above two plug-ins, you need to add some configuration to the editor.

Considering the scenario of multi person development, and everyone’s development tool configuration is different, I put the following configuration in the project root directory and add it to git version control, so that everyone has this configuration when they get the project.

The path is:your_project/.vscode/settings.json

{
  "files.associations": {
    "*.wxss": "css",
    "*.wxs": "javascript",
    "*.acss": "css",
    "*.axml": "html",
    "*.wxml": "html",
    "*.swan": "html"
  },
  "files.trimTrailingWhitespace": true,
  "eslint.workingDirectories": [{ "mode": "auto" }],
  "Eslint. Enable": true, // whether to enable eslint of vscode
  "eslint.options": {
    //Specifies the suffix of the file processed by the eslint of vscode
    "extensions": [".js", ".ts", ".tsx"]
  },
  "eslint.validate": ["javascript"],
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "git.ignoreLimitWarning": true
}

2、 It’s about to start

1. yarnInitialization generationpackage.json

Make prettier format wxss with one click (Part 1)

2. Install dependencies related to eslint and prettier

If you want to use eslint, you often need to configure many complex rules. If everyone wants to do this, it will obviously consume a lot of energy. So someone came forward and opened their code specification library on GitHub. The more popular ones are airbnb, standard, prettier, etc.

Here I choose the eslint config alloy open source specification library produced by the domestic Tencent alloyteam team.

In fact, their team first used airbnb rules, but because it was too strict, some rules still needed to be personalized, resulting in more and more changes, and finally decided to maintain a new set. After more than two years of polishing, eslint config alloy is now very mature.

I chose it for several reasons:

  • For react / Vue / typescript projects
  • Rules related to styles are managed by prettier
  • There are Chinese documents and website examples (my poor English level is very attractive to me, ha ha)
  • It updates quickly and has officially maintained Vue, typescript and react + typescript rules
$ yarn add --dev [email protected]
$ yarn add --dev [email protected]
$ yarn add --dev [email protected]
$ yarn add --dev [email protected]
$ yarn add --dev [email protected]
$ yarn add --dev [email protected]
$ yarn add --dev [email protected]
3. After installing the dependency, add the configuration files of eslint and prettier

There can be many kinds of configuration files. The JavaScript formats used here are.eslintrc.js.prettierrc.js, are placed in the project root directory.

I won’t expand on the configuration. If you have any doubts, you can search for answers or comment to me.

// .eslintrc.js
module.exports = {
  root: true,
  parser: 'babel-eslint',
  env: {
    browser: true,
    es6: true,
    node: true,
    commonjs: true
  },
  extends: ['alloy'],
  plugins: ['prettier'],
  globals: {
    Atomics: 'readonly',
    SharedArrayBuffer: 'readonly',
    __DEV__: true,
    __WECHAT__: true,
    __ALIPAY__: true,
    App: true,
    Page: true,
    Component: true,
    Behavior: true,
    wx: true,
    my: true,
    swan: true,
    getApp: true,
    getCurrentPages: true
  },
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module'
  },
  rules: {
    'no-debugger': 2,
    'no-unused-vars': 1,
    'no-var': 0,
    'no-param-reassign': 0,
    'no-irregular-whitespace': 0,
    'no-useless-catch': 1,
    'max-params': ['error', 3],
    'array-callback-return': 1,
    eqeqeq: 0,
    indent: ['error', 2, { SwitchCase: 1 }]
  }
}
// .prettierrc.js
module.exports = {
  printWidth: 120,
  tabWidth: 2,
  useTabs: false,
  semi: false,
  singleQuote: true,

  //The key of the object is quoted only when necessary
  quoteProps: 'as-needed',

  //JSX does not use single quotes, but double quotes
  jsxSingleQuote: false,

  //Comma is not required at the end
  trailingComma: 'none',

  //Spaces are required at the beginning and end of braces
  bracketSpacing: true,

  //The inverse angle brackets of JSX tags need to wrap
  jsxBracketSameLine: false,

  //When the arrow function has only one parameter, there is no need for parentheses
  arrowParens: 'avoid',

  //The format range of each file is the whole content of the file
  rangeStart: 0,

  rangeEnd: Infinity,

  //You do not need to write @ prettier at the beginning of the file
  requirePragma: false,

  //There is no need to automatically insert @ prettier at the beginning of the file
  insertPragma: false,

  //Use default line break criteria
  proseWrap: 'preserve',

  //Determines whether HTML should be folded or not according to the display style
  htmlWhitespaceSensitivity: 'css',

  //Line breaks use LF
  endOfLine: 'lf'
}
4. Configure eslint and prettier ignore rules

The corresponding file is.eslintignore.prettierignore, the same are placed in the project root directory.

These are adjusted according to the actual situation of the project. The following is for reference only:

# .eslintignore

*.min.js
typings
node_modules
# .prettierignore

*.min.js
/node_modules
/dist
# OS
.DS_Store
.idea
.editorconfig
.npmrc
package-lock.json
# Ignored suffix
*.log
*.md
*.svg
*.png
*ignore
## Built-files
.cache
dist
5. Add.editorconfigconfiguration file

It is used to smooth out the differences between different editors. It is also placed in the project root directory.

# .editorconfig
# http://editorconfig.org
# https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties


#For the configuration file in the root directory, the editor will look up from the current directory. If a file with 'roor = true' is found, it will not be searched again
root = true

#Match all files
[*]
#Indentation style: Space
indent_style = space
#Indent size 2
indent_size = 2
#Newline LF
end_of_line = lf
#Character set UTF-8
charset = utf-8
#Do not leave spaces at the end of the line
trim_trailing_whitespace = true
#Add a blank line at the end of the file
insert_final_newline = true
#Operator has spaces twice
spaces_around_operators = true

#Effective for all JS files
[*.js]
#Use single quotes for Strings
quote_type = single

[*.md]
trim_trailing_whitespace = false
6. Add NPM scripts

Add three script instructions:

  • "eslint": "eslint ./ --ext .js"
  • "eslint:fix": "eslint --fix ./ --ext .js"
  • "prettier:fix": "prettier --config .prettierrc.js --write './**/*.{js,css,less,scss,json}'"

adoptyarn run <command>You can perform one click formatting and repair. Of course, eslint is used--fixOnly a part can be repaired, and the rest can only be solved manually.

{
  "name": "wechat_applet_demo",
  "version": "1.0.0",
  "Description": "wechat applet demo",
  "main": "app.js",
  "repository": "[email protected]:toFrankie/wechat_applet_demo.git",
  "author": "Frankie <[email protected]>",
  "license": "MIT",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "eslint": "eslint ./ --ext .js",
    "eslint:fix": "eslint --fix ./ --ext .js",
    "prettier:fix": "prettier --config .prettierrc.js --write './**/*.{js,css,less,scss,json}'"
  },
  "devDependencies": {
    "babel-eslint": "10.0.3",
    "eslint": "6.7.1",
    "eslint-config-alloy": "3.7.1",
    "eslint-config-prettier": "6.10.0",
    "eslint-plugin-prettier": "3.1.4",
    "prettier": "2.0.5",
    "prettier-eslint-cli": "5.0.0"
  }
}

3、 You think it’s over?

Before looking down, it is necessary to explain:

The next step involves gulp.js, so that prettier can process gulp.js conversioncssTo achieve the final prettier formattingwxssPurpose.

However, I did take some detours in the above methods. In fact, it can be specified through prettier configuration overrides configuration.wxssThe extension file uses the specified parser. In other words, we can deal with.wxssJust use CSS parser to process the file( See the ending of the series)

But my suggestion is to finish the first two articles and then look at the ending.

No, no, no, what I want to share most in this article is the following. The previous content is relatively simple and many people understand it.

Prettier supports code formatting of JavaScript, JSX, angular, Vue, flow, typescript, CSS, less, SCSS, HTML, JSON, graphql, markdown (GFM, mdx) and yaml.

But I can’t recognize itwxssacssAnd other applets. Although their rules are the same as CSS, prettier does not have a parser to parse them.

We tried to adjust the script command to (add)*.wxssFile with extension:

{
  "scripts": {
    "prettier:fix": "prettier --config .prettierrc.js --write './**/*.wxss'",
  }
}

Then, an error will be reported when executing, as follows:

[error] No parser could be inferred for file: app.wxss

Since this doesn’t work, you can’t format one by one using the prettier plug-in of vs code*.wxssThe workload is too heavy, which is not in line with our practice of “laziness”.

So how to solve it?

I use gulp.js to handle it.If you are not familiar with gulp, click here to learn about it.

4、 Gulp.js

To put it simply, gulp.js works in the same way as node.jsstream(flow), first get the requiredstream, and then throughstreamofpipe()Method to import the stream to the place you want. For example, in the gulp plug-in, the streams processed by the plug-in can be imported into other plug-in summaries. Of course, the streams can also be written to files, so gulp is based onstreamFor media, it does not need to generate temporary files frequently, which is one reason why gulp is faster than grunt.

My initial thought was: first of allwxssacss)Convert and export tocss, then deletewxssacss)File, and then use prettier paircssFormat the file and turn it backwxssacss)Then delete itcssFile. This process will frequently generate temporary files. The idea is a bit like grunt.

However, after understanding gulp’s idea, in fact, it helps us eliminate the link of frequent addition and deletion of files. It will be faster to operate all in memory, so I rejected the previous scheme.

Next, we only use two APIs of gulp,gulp.src()andgulp.dest()

1. gulp.src()

This method is used to obtain the stream, but it should be noted that the content in the stream is not the original file stream, but a virtual file object stream. This virtual file object stores the path, file name, content and other information of the original file( It’s not in-depth here. I’m interested in understanding it by myself)

Syntax: gulp. SRC (globs [, options])

  • globs: is a file matching pattern used to match file paths (including file names)
  • options: is an optional parameter, which is not needed in general

*Please refer to the document for detailed description of parameters.

2. gulp.dest()

This method is used to write files

gulp.dest(path[, options])

  • path: is the path to write to the file
  • options: is an optional parameter, which is not needed in general

If you want to use it wellgulp.dest()This method needs to understand the relationship between the path parameters passed in to it and the final generated file.

Gulp is generally used throughgulp.src()Method to get the file stream we want to process, and then pass the file stream throughpipe()Method is imported into gulp’s plug-in, and finally the flow processed by the plug-in is passed throughpipe()Method import togulp.dest()In,gulp.dest()Method writes the contents of the stream to a file.

One thing that needs to be clear here is that we givegulp.dest()The passed in path parameter can only be used to specify the directory of the file to be generated, not the file name of the generated file. The file name of the generated file uses the file name of the file stream imported into it, so the generated file name is determined by the file stream imported into it, even if we pass in a path parameter with file name, Then it will also take the file name as the directory name, for example:

const gulp = require('gulp')
gulp.src('script/jquery.js').pipe(gulp.dest('dist/foo.js'))

//The final generated file path is dist / foo.js/jquery.js instead of dist / foo.js

If you need to modify the file name, you need to use the plug-in gulp rename.

  • For the API and method description of gulp, please refer to an article in the official document and unparalleled.

5、 Start configuration

First, install gulp dependent packages.

$ yarn add --dev [email protected]
$ yarn add --dev [email protected]
$ yarn add --dev [email protected]
$ yarn add --dev [email protected]
$ yarn add --dev [email protected]

Next, we create a project under the project root directorygulpfile.jsFile.

The quick start tutorial on gulp.js official website is very simple and will not be repeated here.

Idea: usegulp.src()Get the stream, and then use the gulp plug-in to rename and format the stream respectively(gulp-prettier). rename it again(gulp-rename). final export(gulp.dest())。 Utilization in the processgulp-debugPlug in to view some information.

Here I deal with the WeChat applet and the cascading style of Alipay applet.

// gulpfile.js
const { series, parallel, src, dest } = require('gulp')
const rename = require('gulp-rename')
const debug = require('gulp-debug')
const clean = require('gulp-clean')
const prettier = require('gulp-prettier')
const config = require('./.prettierrc')

//Wxss one click Format
const wxssPrettier = () => {
  return src('./**/*.wxss')
    .pipe(
      //You can use the plug-in to view some debug information
      debug()
    )
    .pipe(
      //Rewrite the extension to CSS to be recognized and resolved by prettier
      rename({
        extname: '.css'
      })
    )
    .pipe(
      //Prettier formatting
      prettier(config)
    )
    .pipe(
      //Change the extension to wxss again
      rename({
        extname: '.wxss'
      })
    )
    .pipe(
      //Export file
      dest(__dirname)
    )
}

//ACSS one click Format
const acssPrettier = () => {
  return src('./**/*.acss')
    .pipe(debug())
    .pipe(
      rename({
        extname: '.css'
      })
    )
    .pipe(prettier(config))
    .pipe(
      rename({
        extname: '.acss'
      })
    )
    .pipe(dest(__dirname))
}

//Multiple tasks are exported here and can be called through gulp XXX, such as gulp all
//The series and parallel APIs are executed sequentially (synchronous) and simultaneously (parallel)
module.exports = {
  all: parallel(wxssPrettier, acssPrettier),
  wxss: wxssPrettier,
  acss: acssPrettier
}

Just call it in the following way

// package.json
{
  "scripts": {
    "prettier:wxss": "gulp wxss",
    "prettier:accs": "gulp acss",
    "prettier:wxss:acss": "gulp all"
  }
}

After executing the command, we see the following results, indicating that the configuration is successful.
Make prettier format wxss with one click (Part 1)

6、 Git hooks

The above has been realizedwxssacssThe file with the extension is formatted with one click.

You can also be “lazier”. We can realize it by using git hookscommitBefore, perform eslint and prettier detection and formatting on the project. Once an error occurs, it will stopcommitOperation.

As this article is already very long, we will continue to write in the next article

7、 A digression

Since the NPM package of this project is only used for code checking and formatting, it does not participate in the page code logic. So I add the packaging configuration option to the applet local project configuration file.

Packoptions is used to configure options for items during packaging. Packaging is a necessary step for previewing and uploading projects.

You can now specifypackOptions.ignoreField to configure that files or folders that meet the specified rules are ignored during packaging to skip the packaging process. These files or folders will not appear in the preview or upload results.

* the Alipay applet needs to be paid attention.ignoreOptions.

// project.config.js
{
  "packOptions": {
    "ignore": [
      {
        "type": "regexp",
        "test": "\\.md$"
      },
      {
        "type": "folder",
        "test": "node_modules"
      }
    ]
  }
}