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 time
2781ms
- The third time
2827ms
- For the fourth time
2797ms
Version: webpack 5.0.0 – beta. 9
Persistent caching is used
- For the first time,
3567ms
- The second time
2602ms
- The third time
2609ms
- For the fourth time
2582ms
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
- Cannot add property htmlWebpackPluginAlterChunks, object is not extensible
Install 4.x version fixable
NPM I [email protected]Copy the code
- 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