This is the second article after the previous one about building a large project from scratch with WebPack step by step. This paper uses Webpack5 to reconstruct the project, and uses webpack-chain to configure Webpack. Each function is also an independent file, which can be used independently. So the configuration of this project can be used in any project. This project can also be used as a Webpack manual to learn. I developed this project so that you can learn from it whether you are a novice or an experienced master. This project provides a good practical platform for students who want to learn Webpack. Each plug-in and each loader will have detailed explanation and usage background.

In order to save you time, improve the learning efficiency, I would like to integrate all webpack related series here, here every optimization is after I weigh to practice, also can learn some excellent open source libraries to improve it, this project will maintain for a long time, also sincerely welcome all people involved in the project, become the project to build together!

Project address: github.com/luoxue-vict…

Since this article was refactored using webpack5, I’ll leave lesson 14 up front

This article directory

  • 课时 14: upgrade webpack5
  • Topic 10: Adding ESLint and enabling auto repair
  • Topic 11: Add stylelint and enable automatic repair
  • Topic 12: Adding TSLint and enabling automatic repair
  • Topic 13: Configuring aliases
  • 课时 15: define general variables
  • Lesson 16: Strictly distinguish the case of paths
  • 课时 17: loading resources images, SVG, media, fonts
  • Lesson 18: Set global Styles
  • Vscode configuration
  • Prettier configuration

Next planned TODO github.com/luoxue-vict…

课时 14: upgrade webpack5

This chapter focuses on upgrading the project to webpack5. Step on the pit first. I want to share with you how I stepped on the pit.

Webpackage 5 is more of a black box, and a lot of work that had to be done with plug-ins is now integrated inside webPackage 5, right out of the box. Webpack 5 is designed to optimize compilation speed, more default configurations (more configurations are built in), better code generation, and pave the way for further development of WebPack in the future.

This chapter summary

  • What does webpack5 do?
  • Upgrade webpack5
  • Compilation speed comparison
  • Changes from webpack4 to webpack5

What does webpack5 do?

  • Use long-term caches to improve compilation speed
  • Use better algorithms and defaults to improve long-term caching
  • Improve bundle size with better Tree Shaking and Code Generation
  • Refactor the internal structure to implement the functionality of V4 without introducing any major changes
  • Prepare for future functionality by introducing significant changes that will allow us to use V5 for as long as possible

Upgrade webpack5

This tutorial can be upgraded/degraded with the scaffolding command in one click

webpack-box upgrade 5/4
Copy the code

Two plug-ins have been mainly upgraded, and other modules used have been compatible. Html-webpack-plugin involves hot update, and the bug of hot update has not been fixed yet, so the first compilation after switching to Webpack5 can be successful. However, recompiling after saving will report an error (I will keep an eye on this and update the version as soon as it is fixed)

package.json

{
  "html-webpack-plugin": 11 "^ 4.0.0 - beta."."webpack": 9 "^ 5.0.0 - beta."
}
Copy the code

Compilation speed comparison

webpack-box build index
Copy the code

Version: webpack 4.41.2

Cache-loader is used below

  • For the first time,4216ms
  • The second time2781ms
  • The third time2827ms
  • For the fourth time2797ms

Version: webpack 5.0.0 – beta. 9

Persistent caching is used

  • For the first time,3567ms
  • The second time2602ms
  • The third time2609ms
  • For the fourth time2582ms

It can be seen that the compilation speed of Webpack5 using persistent cache is 100ms ~ 200ms faster than that of WebPack4 using cache-loader. Therefore, there is no need to use cache-loader in the future. Webpack5 provides better algorithms and better caching solutions

Changes from webpack4 to webpack5

1. Cache-loader is no longer needed

With persistent caching, you no longer need a cache loader. Same as Babel cacheDirectory.

2. The problem of HTML – webpack – the plugin

Some errors and fix errors

  1. Cannot add property htmlWebpackPluginAlterChunks, object is not extensible

Install 4.x version fixable

NPM I [email protected]Copy the code
  1. Cannot read property ‘get’ of undefined

The first compilation takes effect, but an error will be reported after saving. Webpack5 overwrites the hot update, resulting in incompatibility of htML-webpack-plugin

3. The dynamically loaded file finally has a name, no longer an ID, but a concatenation of the project path

This can be modified using optimization.chunkids

Click to see the document

module.exports = {
  / /...
  optimization: {
    chunkIds: "named"}};// Chain modification
config.optimization.set("chunkIds"."natural");
Copy the code

4. A nested tree – shaking

In Webpackage 4, both A and B are packaged into the bundle, and Webpackage 5 removes nested useless code, meaning that B is not packaged into the bundle because B is not used

// inner.js
export const a = 1;
export const b = 2;

// module.js
import * as inner from "./inner";
export { inner };

// user.js
import * as module from "./module";
console.log(module.inner.a);
Copy the code

5. Internal module tree-shaking

Webpack5 checks to see if any methods inside the module are being used, and if they are not, the methods called inside the module are removed

However, if you know that the code has no side effects, it is very likely that your code will be removed. For example, if you are writing a component and your library does not use it, it will be tree-shaking when you package it

To use it you need to configure “sideEffects”: false in package.json and set optimization.usedexports to true

// package.json
{
  "sideEffects": false
}

// config/optimization.js
config.optimization.usedExports(true);
Copy the code

Code demo

import { something } from "./something";

function usingSomething() {
  return something;
}

export function test() {
  return usingSomething();
}
Copy the code

If the external module does not use the test method, usingSomething or something will also be deleted from the bundle

6. Improve code generation

Tells WebPack the maximum EcmaScript version of the code generated by WebPack

Webpack4 supports only ES5. Webpack5 supports ES5 and ES6

The value of ecmaVersion ranges from 5 to 11 or from 2009 to 2020. The default value of WebPackage 5 is 5

config.output.set("ecmaVersion".6);
Copy the code

7. SplitChunks and Module Sizes

Webpack5 can set the size of splitChunks for different types of files. By default, splitChunks are packaged only for javascript

config.optimization.splitChunks({
  minSize: {
    javascript: 30000.style: 50000}});Copy the code

8. Persistent caching

Webpack5 provides two cache methods: persistent cache caches files to the file system, and cache files in memory

// type {filesystem | memory}
config.cache({
  type: "filesystem"
});
Copy the code

By default, it is cached under node_modules/. Cache /webpack, and you can modify the cache directory with the cacheDirectory option

9. Other

Webpack5 adjusts the content here

Topic 10: Adding ESLint and enabling auto repair

This chapter summary

  • The CWD layer is removed and the functions are simplified
  • Configuration eslint – loader
  • Eslint automatically fixes
  • Add scaffold command
  • Use the compiler to automatically fix
  • Code Commit Checking (Lint-Staged)

The CWD layer is removed and the functions are simplified

Purpose: Make functions clearer, do one thing for each layer, and use standardized apis to handle the same logic

  • PluginAPI handles scaffold plug-in logic
  • The CommandAPI handles scaffold command-line logic
  • CWD extracts the Command layer
API │ └ ─ ─ ─ ─ CommandAPI. Js └ ─ ─ PluginAPI. Js └ ─ ─ CWD │ ─ ─ the build: SSR. Js │ ─ ─ build. Js │ ─ ─ dev. Js │ ─ ─ DLL. Js │ ─ ─ lint. Js └ ─ ─ ssr:server.jsCopy the code

Configuration eslint – loader

Configure esLint-loader to check for ESLint rules during Webpack-box dev and display any errors on the console

config.module
  .rule("eslint")
  .pre()
  .exclude.add(/node_modules/)
  .end()
  .test(/\.(vue|(j)sx?) $/)
  .use("eslint-loader")
  .loader(require.resolve("eslint-loader"))
  .options({
    extensions,
    cache: true,
    cacheIdentifier,
    emitWarning: allWarnings,
    emitError: allErrors,
    eslintPath: path.dirname(
      resolveModule("eslint/package.json", cwd) ||
        resolveModule("eslint/package.json", __dirname)
    ),
    formatter: loadModule("eslint/lib/formatters/codeframe", cwd, true)});Copy the code

Eslint automatically fixes

When a rule is changed in a project, there will be a lot of errors in the project and we don’t want to manually fix them one by one, so we need to use esLint’s auto-fix feature, which will help us fix the majority of errors and manually fix those that can’t be fixed

Part of the code is written here, more details can be found in the project

packages/eslint/lint.js

const { CLIEngine } = loadModule("eslint", cwd, true) | |require("eslint");
const config = Object.assign({
  extensions,
  fix: true,
  cwd
});
const engine = new CLIEngine(config);
const defaultFilesToLint = ["src"."tests"."*.js".".*.js"].filter(pattern= >
  globby
    .sync(pattern, { cwd, absolute: true })
    .some(p= >! engine.isPathIgnored(p)) );const files = args._ && args._.length ? args._ : defaultFilesToLint;
const report = engine.executeOnFiles(files);
if (config.fix) {
  CLIEngine.outputFixes(report);
}
Copy the code

Add scaffold command

We want to fix it from the command line, webpack-box lint esLint, so we need to add the command line to the CWD layer

cwd/lint.js

module.exports = function(injectCommand, api) {
  injectCommand(function({ program, cleanArgs, boxConfig }) {
    program
      .command("lint [type]")
      .description("Repair lint")
      .action(async (name, cmd) => {
        const options = cleanArgs(cmd);
        const args = Object.assign(options, { name }, boxConfig);
        require(".. /build/lint")(args, api);
      });
  });
};
Copy the code

Eslint fixes most errors using webpack-box Lint

Use the compiler to automatically fix

Of course we can fix some bugs when we run webpack-box lint eslint, but when we write code we expect the compiler to fix it automatically, rather than waiting until the code is finished to verify it, which can cause us to have a second problem and even cause problems that can’t be fixed.

So let’s use vscode’s eslint plugin to help us do that

The first compiler you must use is vscode, of course other compilers can also be used, but we will only cover vscode configuration here.

After installing the ESLint plugin, you need to set “eslint. AutoFixOnSave “: true in your Settings so that esLint errors can be fixed automatically when saved

Of course, you might only use ESLint in this project and fix it when you don’t need to save it in other projects

You can add it in the root directory

└ ─ ─. Vscode └ ─ ─ Settings. The jsonCopy the code

Put a copy of my own configuration for your reference

{
  /* * @description compiler configuration * @param tabSize default TAB is two Spaces * @param formatOnSave save automatically fixed */
  "editor.tabSize": 2."editor.formatOnSave": true./* * @description esLint configured * @param alwaysShowStatus configured * @param autoFixOnSave automatically fixed when saved * @param validate added error message in vue */
  "eslint.alwaysShowStatus": true."eslint.autoFixOnSave": true."eslint.validate": [
    "javascript"."javascriptreact",
    {
      "language": "vue"."autoFix": true}].@ the description / * * * @ tslint configuration param autoFixOnSave saved automatically repair * @ param alwaysShowRuleFailuresAsWarnings all characteristics is done with Warnings * /
  "tslint.autoFixOnSave": true."tslint.alwaysShowRuleFailuresAsWarnings": true./* * @description stylelint configuration * @param autoFixOnSave Automatically fixes when saving */
  "stylelint.autoFixOnSave": true./* * @description vetur configuration */
  "vetur.format.defaultFormatter.html": "prettier"."vetur.format.defaultFormatterOptions": {
    "prettier": {
      "semi": false."singleQuote": true}},/* * @description configures the editor Settings to override a language */
  "[typescript]": {
    // "editor.defaultFormatter": "esbenp.prettier-vscode"
    "editor.defaultFormatter": "eg2.tslint"
  },
  "[html]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[jsonc]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[vue]": {
    "editor.defaultFormatter": "eg2.tslint"
  },
  "[javascript]": {
    "editor.defaultFormatter": "dbaeumer.vscode-eslint"
  },
  "[javascriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"}}Copy the code

Code Commit Checking (Lint-Staged)

All of the above is ideal for checking and fixing, but sometimes we can run into unexpected situations and commit without lint code, which can lead to problems, so we need to do a code check before committing

Add Lint-staged code to package.json so that lint will be executed before the code commits and Lint will pass

package.json

{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"}},"lint-staged": {
    "*.{js,jsx}": ["webpack-box lint eslint"."git add"]}}Copy the code

Topic 11: Add stylelint and enable automatic repair

This chapter summary

  • The stylelint Standard plug-in is configured
  • The stylelint plug-in is configured
  • Auto repair
  • Code submission check

The stylelint Standard plug-in is configured

Use the stylelint-config-standard plug-in

.stylelintrc.js

module.exports = {
  root: true.extends: "stylelint-config-standard"
};
Copy the code

The stylelint plug-in is configured

module.exports = ({
  config,
  options: { stylelint: { lintOnSave = false, extensions } = {} },
  api
}) = > {
  const StyleLintPlugin = require("stylelint-webpack-plugin");
  const CodeframeFormatter = require("stylelint-codeframe-formatter");
  const stylelint = [];
  return () = > {
    config.plugin("stylelint").use(StyleLintPlugin, [
      Object.assign(
        {
          failOnError: lintOnSave === "error".files: ["src/**/*.{vue,htm,html,css,sss,less,scss}"].formatter: CodeframeFormatter
        },
        stylelint
      )
    ]);
  };
};
Copy the code

Auto repair

module.exports = async function lint({ api, args = {}, pluginOptions = {} }) {
  const cwd = api.resolve(".");

  const files =
    args._ && args._.length
      ? args._
      : [cwd + "/src/**/*.{vue,htm,html,css,sss,less,scss}"];
  if (args["no-fix"]) {
    args.fix = false;
    delete args["no-fix"];
  }

  const { formatter } = args;
  if (
    formatter &&
    typeof formatter === "string" &&
    !["json"."string"."verbose"].includes(formatter)
  ) {
    try {
      args.formatter = require(formatter);
    } catch (e) {
      delete args.formatter;
      if (typeofpluginOptions.formatter ! = ="function") {
        console.log(
          format(
            chalk`{bgYellow.black WARN }`,
            chalk`${e.toString()}\n{yellow Invalid formatter}`)); }}}const options = Object.assign(
    {},
    {
      configBasedir: cwd,
      fix: true,
      files,
      formatter: CodeframeFormatter
    },
    pluginOptions,
    normalizeConfig(args)
  );

  try {
    const { errored, results, output: formattedOutput } = await stylelint.lint(
      options
    );
    if(! errored) {if(! args.silent) {const hasWarnings = results.some(result= > {
          if (result.ignored) {
            return null;
          }
          return result.warnings.some(
            warning= > warning.severity === "warning"
          );
        });
        if (hasWarnings) {
          console.log(formattedOutput);
        } else {
          console.log(
            format(
              chalk`{bgGreen.black DONE }`.'Stylelint found no errors!${
                options.fix ? chalk'{blue (already fixed automatically)}' : ""
              }`)); }}}else {
      console.log(formattedOutput);
      process.exit(1); }}catch (err) {
    console.log(
      format(chalk`{bgRed.black ERROR }`, err.stack.slice(" Error:".length))
    );
    process.exit(1); }};Copy the code

Code submission check

{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"}},"lint-staged": {
    "*.{vue,htm,html,css,sss,less,scss}": [
      "webpack-box lint stylelint"."git add"]."*.{js,jsx}": ["webpack-box lint eslint"."git add"]}}Copy the code

Topic 12: Adding TSLint and enabling automatic repair

This chapter summary

  • Configure the plug-in
  • Add rules
  • Automatic repair function
  • Submit inspection

Configure the plug-in

config/tslintPlugin.js

module.exports = ({
  config,
  options: { tslint: { lintOnSave = false, useThreads = false } = {} },
  api
}) = > {
  const fs = require("fs");
  return () = > {
    config.plugin("fork-ts-checker").tap(([options]) = >{ options.tslint = lintOnSave ! = =false && fs.existsSync(api.resolve("tslint.json"));
      options.formatter = "codeframe";
      options.checkSyntacticErrors = useThreads;
      return [options];
    });
  };
};
Copy the code

Add rules

tslint.json

{
  "defaultSeverity": "warning"."extends": ["tslint:recommended"]."linterOptions": {
    "exclude": ["node_modules/**"]},"rules": {
    "max-classes-per-file": [true.5."exclude-class-expressions"]."quotemark": [true."single"]."semicolon": [true."never"]."indent": [true."spaces".2]."ordered-imports": false."object-literal-sort-keys": false."no-consecutive-blank-lines": false."disable-next-line": false."only-arrow-functions": false."radix": false."class-name": false."eofline": false."no-unused-expression": false."no-console": false."trailing-comma": false."interface-name": false}}Copy the code

Automatic repair function

const { done } = require("@vue/cli-shared-utils");

module.exports = function lint({ args = {}, api, silent }) {
  const options = {
    fix: args.fix ! = =false.formatter: args.format || "codeFrame".formattersDirectory: args["formatters-dir"].rulesDirectory: args["rules-dir"]};const program = tslint.Linter.createProgram(api.resolve("tsconfig.json"));
  const linter = new tslint.Linter(options, program);

  const updateProgram = linter.updateProgram;
  linter.updateProgram = function(. args) {
    updateProgram.call(this. args); patchProgram(this.program);
  };

  const tslintConfigPath = tslint.Configuration.CONFIG_FILENAMES.map(filename= >
    api.resolve(filename)
  ).find(file= > fs.existsSync(file));

  const config = tslint.Configuration.findConfiguration(tslintConfigPath)
    .results;

  const lint = file= > {
    const filePath = api.resolve(file);
    const isVue = isVueFile(file);
    patchWriteFile();
    linter.lint(filePath, "", isVue ? vueConfig : config);
    restoreWriteFile();
  };

  const files =
    args._ && args._.length
      ? args._
      : [cwd + "/src/**/*.ts", cwd + "/src/**/*.vue", cwd + "/src/**/*.tsx"];

  return globby(files, { cwd }).then(files= > {
    files.forEach(lint);
    if (silent) return;
    const result = linter.getResult();
    if (result.output.trim()) {
      process.stdout.write(result.output);
    } else if (result.fixes.length) {
      const f = new tslint.Formatters.ProseFormatter();
      process.stdout.write(f.format(result.failures, result.fixes));
    } else if(! result.failures.length) { done("Tslint found no error.\n");
    }

    if(result.failures.length && ! args.force) { process.exitCode =1; }}); };Copy the code

Submit inspection

{
  "lint-staged": {
    "*.{vue,htm,html,css,sss,less,scss}": [
      "webpack-box lint stylelint"."git add"]."*.{ts,tsx}": ["webpack-box lint tslint"."git add"]."*.{js,jsx}": ["webpack-box lint eslint"."git add"]}}Copy the code

Topic 13: Configuring aliases

In our work, if a file needs to be copied to another directory, then the file’s reference dependency may have path errors. Also, we don’t like to have to go layer by layer every time we introduce a dependency, we want to be able to have an alias to specify a directory no matter where we use it.

This chapter summary

  • Use aliases in projects
  • Configure an alias
  • Webpack implementation
  • Compiler jump configuration

Use aliases in projects

src/main.js

import { cube } from "./treeShaking";
import { cube } from "@/treeShaking";
import { cube } from "@src/treeShaking";
Copy the code

Configure an alias

alias: {
  The '@': resolve('src'),
  '@src': resolve('src')}Copy the code

Webpack implementation

module.exports = ({ config, options, resolve }) = > {
  const fs = require("fs");
  const conf = options.alias;
  return () = > {
    // Generate default aliases
    const dirs = fs.readdirSync(resolve("src"));
    let aliasConfig = config.resolve.extensions
      .merge([".mjs".".js".".jsx".".vue".".ts".".json".".wasm"])
      .end().alias;
    dirs.forEach(v= > {
      const stat = fs.statSync(resolve(`src/${v}`));
      if (stat.isDirectory()) {
        aliasConfig = aliasConfig.set(` @${v}`, resolve(`src/${v}`)); }});// The user configures the alias
    if (conf.alias) {
      const keys = Object.keys(conf.alias);
      keys.forEach(key= > {
        aliasConfig = aliasConfig.set(key, conf.alias[key]);
      });
    }

    // Set a custom alias
    aliasConfig.set("@", resolve("src")).set("@src", resolve("src"));
  };
};
Copy the code

Compiler jump configuration

If you are using TS, the type will be lost after the alias is configured, indicating that the module can not be found, so we need to configure the corresponding alias in the compiler

tsconfig.json/jsconfig.json

{
  "compilerOptions": {
    "baseUrl": "."."rootDir": "."."paths": {
      "@src/*": [
        "src/*"]."@ / *": [
        "src/*"].}}}Copy the code

课时 15: define general variables

Sometimes we need a communication bridge between the scaffolding and the business code

For example, when we run our NPM build, we are running in production environment. I want to do some special logic in production environment in main.js. However, main.js is executed on the browser side, while NPM run build runs on the Node side. There is no way to communicate between the two sides. So what do we do?

Webpack provides us with a plugin, EnvironmentPlugin, that compiles the values of variables we define on the Node side into code at compile time, for example

In main.js, we’ve written code that looks common in Node, but is unrecognizable in browsers, which don’t have process objects, and will report errors as expected

main.js

if (process.env.NODE_ENV === "production") {
  console.log("Welcome to production");
}
Copy the code

We configure webpack EnvironmentPlugin plug-ins

const webpack = require("webpack");

module.exports = ({ config, resolve, options }) = > {
  return () = > {
    const resolveClientEnv = require(".. /util/resolveClientEnv");
    config
      .plugin("process-env")
      .use(webpack.EnvironmentPlugin, [resolveClientEnv(options)]);
  };
};
Copy the code

util/resolveClientEnv.js

module.exports = function resolveClientEnv(options, raw) {
  const env = {};
  if (process.env) {
    Object.keys(process.env).forEach(key= > {
      if (key === "NODE_ENV") { env[key] = process.env[key]; }}); }if (options.env) {
    Object.assign(env, options.env);
  }
  return env;
};
Copy the code

Let’s run NPM build and see what dist/index.bundle.js compiles

// "production" === "production"
if (true) {
  console.log("Welcome to production");
}
Copy the code

Webpack compiles the values of process.env.node_env in the bundle so that we can run it on the Web side and compile it in production

Lesson 16: Strictly distinguish the case of paths

Sometimes we often have such a situation, obviously there is no problem with local compilation, but there will be an error when Jenkins is compiling online. Such a problem often takes us a long time to find the bug, it turns out that there is a problem with the case of the local path, we are not case-sensitive when quoting the path. For example

└── ├ ─ sci-1.txtCopy the code

The first letter of index. js in the path above is uppercase, but I refer to it in lowercase in main.js

main.js

import Index from "./index.js";
Copy the code

This will not cause an error locally, but when you use Jenkins, you will get an error that the./index.js module is not found

So we need a plugin that checks case strictly while we’re developing so that this doesn’t happen.

We use the case-sensitive paths-webpack-plugin plugin to implement this

module.exports = ({ config, webpackVersion, resolve, options }) = > {
  return () = > {
    // WebPack 5 is incompatible
    if (parseInt(webpackVersion) >= 5) return;
    config
      .plugin("case-sensitive-paths")
      .use(require("case-sensitive-paths-webpack-plugin"));
  };
};
Copy the code

课时 17: loading resources images, SVG, media, fonts

This chapter directly on the code bar, is the previous basic supplement

module.exports = ({ config, webpackVersion, resolve, options }) = > {
  return () = > {
    const getAssetPath = require(".. /util/getAssetPath");
    const inlineLimit = 4096;

    const genAssetSubPath = dir= > {
      return getAssetPath(
        options,
        `${dir}/[name]${options.filenameHashing ? ".[hash:8]" : ""}.[ext]`
      );
    };

    const genUrlLoaderOptions = dir= > {
      return {
        limit: inlineLimit,
        fallback: {
          loader: "file-loader".options: {
            name: genAssetSubPath(dir)
          }
        }
      };
    };

    config.module
      .rule("images")
      .test(/\.(png|jpe? g|gif|webp)(\? . *)? $/)
      .use("url-loader")
      .loader(require.resolve("url-loader"))
      .options(genUrlLoaderOptions("img"));

    config.module
      .rule("svg")
      .test(/\.(svg)(\? . *)? $/)
      .use("file-loader")
      .loader(require.resolve("file-loader"))
      .options({
        name: genAssetSubPath("img")}); config.module .rule("media")
      .test(/\.(mp4|webm|ogg|mp3|wav|flac|aac)(\? . *)? $/)
      .use("url-loader")
      .loader(require.resolve("url-loader"))
      .options(genUrlLoaderOptions("media"));

    config.module
      .rule("fonts")
      .test(/\.(woff2? |eot|ttf|otf)(\? . *)? $/i)
      .use("url-loader")
      .loader(require.resolve("url-loader"))
      .options(genUrlLoaderOptions("fonts"));
  };
};
Copy the code

Lesson 18: Set global Styles

When writing CSS, we wrap commonly used functions/variables etc. into a global.less/ SCSS, and then import it when we need it. Obviously it would be cumbersome and error-prone to import it manually every time (especially if a new member of the group was added), so we thought it would be perfect to automatically import Global into the file.

We need a style-resources-loader to help us do this

Configuration style – resources – loader

config/styleResourceLoader.js

module.exports = ({ config, options }) = > {
  const resourcesOpt = options.resources;
  return () = >{["normal"].forEach(oneOf= > {
      Object.keys(resourcesOpt).forEach(loader= > {
        config.module
          .rule(loader)
          .oneOf(oneOf)
          .use("style-resources-loader")
          .loader("style-resources-loader")
          .options({
            patterns: resourcesOpt[loader].patterns
          });
      });
    });
  };
};
Copy the code

config/style.js

if (loader) {
  let resolvedLoader;
  try {
    resolvedLoader = require.resolve(loader);
  } catch (error) {
    resolvedLoader = loader;
  }
  rule
    .use(loader)
    .loader(resolvedLoader)
    // Options are CSS parameters corresponding to config. You can configure loader parameters by yourself
    .options(Object.assign({ sourceMap }, options));
}
Copy the code

Project configuration

box.config.js

{
  "css": {
    "sourceMap": true.// Whether to enable CSS source Map
    "loaderOptions": { // Configure loader options
      "css": {},
      "less": {
        "globalVars": { // less sets global variables
          "gray": "#ccc"}},"sass": {},
      "postcss": {},
      "stylus": {}},"isCssModule": false.// Whether to modularize the CSS
    "needInlineMinification": false // Whether the CSS needs to be compressed
  },
  "resources": {
    "less": {
      "patterns": [path.resolve(__dirname, "./src/global/*.less")]},"scss": {
      "patterns": [path.resolve(__dirname, "./src/global/*.scss")]}}}Copy the code

use

└ ─ ─ ─ ─ the SRC │ ─ ─global│ ├ ─ 07.02.00, ├ ─ 07.02.00Copy the code

Setting global Styles

global/index.less

.g-less-height () {
  height: 100%;
}

.g-less-test {
  width: 100%;
}
Copy the code

Use global styles

style/index.less

.test {
  width: 300px;
  color: @gray;
  .g-less-height(a); }Copy the code

style/index.scss

.g-scss-test {
  width: 100%;
}
Copy the code

The compiled

dist/css/index.css

.g-less-test {
  width: 100%;
}

.test {
  color: #ccc;
  width: 100%;
  height: 100%;
}

.g-scss-test {
  width: 100%;
}
Copy the code

Visible global styles are packaged into dist/ CSS /index.css, so we don’t have to manually import them every time

Vscode configuration

In the root directory, enable automatic repair esLint/tsLint /stylelint

.vscode/setting.json

{
  /* * @description compiler configuration * @param tabSize default TAB is two Spaces * @param formatOnSave save automatically fixed */
  "editor.tabSize": 2."editor.formatOnSave": true./* * @description esLint configured * @param alwaysShowStatus configured * @param autoFixOnSave automatically fixed when saved * @param validate added error message in vue */
  "eslint.alwaysShowStatus": true."eslint.autoFixOnSave": true."eslint.validate": [
    "javascript"."javascriptreact",
    {
      "language": "vue"."autoFix": true}].@ the description / * * * @ tslint configuration param autoFixOnSave saved automatically repair * @ param alwaysShowRuleFailuresAsWarnings all characteristics is done with Warnings * /
  "tslint.autoFixOnSave":  true."tslint.alwaysShowRuleFailuresAsWarnings": true./* * @description stylelint configuration * @param autoFixOnSave Automatically fixes when saving */
  "stylelint.autoFixOnSave":  true./* * @description vetur configuration */
  "vetur.format.defaultFormatter.html": "prettier"."vetur.format.defaultFormatterOptions": {
    "prettier": {
      "semi": false."singleQuote": true}},/* * @description configures the editor Settings to override a language */
  "[typescript]": {
    // "editor.defaultFormatter": "esbenp.prettier-vscode"
    "editor.defaultFormatter": "eg2.tslint"
  },
  "[html]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[jsonc]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[vue]": {
    "editor.defaultFormatter": "eg2.tslint"
  },
  "[javascript]": {
    "editor.defaultFormatter": "dbaeumer.vscode-eslint"
  },
  "[javascriptreact]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"}}Copy the code

Prettier configuration

Do some formatting in code style with Lint

prettier.config.js

/** * Pretiier standard */
module.exports = {
  // Valid closing comma in ES5 (object, array, etc.)
  trailingComma: "es5".// Instead of indentation, use Spaces
  useTabs: false.// TAB is replaced with two Spaces
  tabWidth: 2.// Semicolons are added only when the syntax might be wrong
  semi: false.// Use single quotes
  singleQuote: true.// Indent script and style tags in Vue files.
  vueIndentScriptAndStyle: true.// A line of up to 100 characters
  printWidth: 100.// The key of the object is quoted only when necessary
  quoteProps: "as-needed".JSX uses double quotes instead of single quotes
  jsxSingleQuote: false.// Spaces are required at the beginning and end of braces
  bracketSpacing: true.// JSX tag Angle brackets require line breaks
  jsxBracketSameLine: false.// Arrow functions with only one argument also need parentheses
  arrowParens: "always".// The range in which each file is formatted is the entire content of the file
  rangeStart: 0.rangeEnd: Infinity.// There is no need to write @prettier at the beginning of the file
  requirePragma: false.// There is no need to automatically insert @prettier at the beginning of a file
  insertPragma: false.// Use the default line folding standard
  proseWrap: "preserve".// Depending on the display style, HTML should be folded or not
  htmlWhitespaceSensitivity: "css".// Use lf for line breaks
  endOfLine: "lf"
};
Copy the code

conclusion

So far, WebPack series 2 has ended, and more wonderful things are still to come. The first two articles can only pave the way for the later big project. I will use Lerna for reconstruction in the future, and use plug-in management to build plug-in ecology to benefit everyone. Vue and React projects will be built later, and even applets, cross-ends, etc will be integrated.

You can bring your ideas to this github.com/luoxue-vict… I will take every issue seriously