Webpack runs in two ways
Install: NPM installWebPackwebpack -cli–save-dev
Method 1: Cli installation
Establish a webpack. Config. Js
const path = require('path');
module.exports = {
entry:'./src/index.js'.output: {filename:'bundle.js'.// Package the resulting file
path:path.resolve(__dirname,'dist') // Package to the dist directory}}Copy the code
Run the command:
"scripts": {
"build": "webpack --config ./webpack.config.js"."dev": "webpack" // Do not write the configuration file. By default, the configuration file in the current working directory is found
}
Copy the code
Note: Wepback does not write configuration files and by default reads webpack.config.js from the current working directory
Mode 2: Node running mode
const path = require('path');
var webpack = require('webpack');
var options = {
mode: 'development'.context: process.cwd(),
entry: './src/index.js'.output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {},
plugins: [
new HtmlWebpackPlugin({
template: './dist/index.html'.// Specify a template file
filename: 'index.html'.// The output file name
inject: false.hash: true.// To avoid caching, you can add hash values to the end of the output resource}),].devServer: {
port: 8080}}var compiler = webpack(options);
Copy the code
The command line is suitable for a project, and Node runs as a scaffold.
Webpack-dev-server (Hot Update)
Purpose: Configures the development server, which can be packaged in memory during implementation and automatically starts the service
npm installwebpack-dev-server–save-dev
Common Usage
Cli mode:
"scripts": {
"build": "webpack --env.production --config ./build/webpack.base"."dev": "webpack-dev-server --env.development --config ./build/webpack.base"
}
Copy the code
Nodejs run
var server = new WebpackDevServer(compiler);
server.listen(8080);
Copy the code
Common configurations:
devServer: {
contentBase: "./build/".// Listen for code changes to automatically commit and refresh the page
host: '0.0. 0. 0',
port: 8080,
open:'true',
disableHostCheck: true,
proxy: { // Configure the proxy
'/web/webApi': {
target: proxyUrl,
secure: false,
changeOrigin: true,
pathRewrite: {'/web/wx' : ''}
}
}
}
Copy the code
HMR (Hot module replacement)
Start the HMR
devServer: {
contentBase: "./dist".open: true.hot:true.HotOnly :true hotOnly: hotOnly:true
},
Copy the code
Plugins add
plugins: [
new webpack.HotModuleReplacementPlugin()
],
Copy the code
Note: CSS stripping does not take effect after HMR is enabled, contenthash, and Chunkhash are not supported
Handle js module HMR
You need to use module.hot.accept to observe module updates to update
if (module.hot) {
module.hot.accept("./b".function() {
document.body.removeChild(document.getElementById("number"));
number();
});
}
Copy the code
- Sensations don’t matter much if they can’t be processed automatically.
Html-webpack-plugin (Page Development)
Single page packaging
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins:[
new HtmlWebpackPlugin({
filename:'index.html', // The name of the packaged filetemplate:path.resolve(__dirname,'.. /public/index.html'), hash:true.// Add a hash stamp to the end of the reference resource
minify:{
removeAttributeQuotes:true // Delete attribute double quotes}})]Copy the code
Note: This method imports all of entry’s JS files into the HTML.
Multi-page packaging
Multiple entries You need to configure multiple entries
entry:{
jquery: ['jquery']./ / packaging jquery
entry1:path.resolve(__dirname,'.. /src/entry-1.js'),
entry2:path.resolve(__dirname,'.. /src/entry-2.js')},output: {filename:'[name].js'.path:path.resolve(__dirname,'.. /dist')},Copy the code
Generate multiple Html files
new HtmlWebpackPlugin({
filename:'index.html'.template:path.resolve(__dirname,'.. /public/template.html'),
hash:true.minify: {removeAttributeQuotes:true
},
chunks: ['jquery'.'entry1'].// Chunk to be imported includes jquery and Entry
}),
new HtmlWebpackPlugin({
filename:'login.html'.template:path.resolve(__dirname,'.. /public/template.html'),
hash:true.minify: {removeAttributeQuotes:true
},
inject:false.// Inject false indicates that js files are not injected
chunksSortMode:'manual'.// Manually configure the code block order
chunks: ['entry2'.'jquery']})Copy the code
The above method is not very elegant. The HtmlPlugin should generate the HTML file dynamically each time you add it manually, like this:
let htmlPlugins = [
{
entry: "entry1".html: "index.html"
},
{
entry: "entry2".html: "login.html"
}
].map(
item= >
new HtmlWebpackPlugin({
filename: item.html,
template: path.resolve(__dirname, ".. /public/template.html"),
hash: true.minify: {
removeAttributeQuotes: true
},
chunks: ["jquery", item.entry]
})
);
plugins: [...htmlPlugins]
Copy the code
Working with CSS files
Parsing CSS styles
We are introducing CSS styles in our JS files!
import './index.css';
Copy the code
When packaging is performed again, the CSS cannot be parsed
ERROR in ./src/index.css 1:4
Module parse failed: Unexpected token (1:4)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
Copy the code
Install the loader
npm install style-loader css-loader --save-dev
Copy the code
module: {
rules: [{test: /\.css$/,
use: ["style-loader"."css-loader"]]}}Copy the code
Extract the style file
By default, style extraction is only done at packaging time
module.exports = env= > {
let isDev = env.development;
const base = {/*source... * /}
if (isDev) {
return merge(base, dev);
} else {
returnmerge(base, prod); }};Copy the code
Install the pull-out plug-in
npm install mini-css-extract-plugin --save-dev
Copy the code
Configure the extraction plug-in
{
test: /\.css$/,
use: [
!isDev && MiniCssExtractPlugin.loader,
isDev && 'style-loader'."css-loader"
].filter(Boolean)}! isDev &&new MiniCssExtractPlugin({
filename: "css/[name].css"
})
Copy the code
The final file configuration is posted below:
const path = require("path");
const dev = require("./webpack.dev");
const prod = require("./webpack.prod");
const merge = require("webpack-merge");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = env= > {
let isDev = env.development;
const base = {
entry: "./src/index.js".output: {
filename: "[name].js".path: path.resolve(__dirname, ".. /dist")},module: {
rules: [{test: /\.css$/,
use: [
!isDev && MiniCssExtractPlugin.loader,
isDev && 'style-loader'."css-loader"
].filter(Boolean)}}],plugins:[
!isDev && new MiniCssExtractPlugin({
filename: "css/[name].css"
}),
new HtmlWebpackPlugin({
filename: "index.html".template: path.resolve(__dirname, ".. /public/template.html"),
hash: true.minify: {
removeAttributeQuotes: true
}
}),
].filter(Boolean)};if (isDev) {
return merge(base, dev);
} else {
returnmerge(base, prod); }};Copy the code
CSS preprocessor
Different CSS preprocessors need to install different Loaders for parsing
- sass: sass-loader node-sass
- less: less-loader less
- stylus: stylus-loader stylus
Using sass
{
test:/\.scss$/,
use:[
!isDev && MiniCssExtractPlugin.loader,
isDev && 'style-loader'."css-loader"."sass-loader"
].filter(Boolean)}Copy the code
A CSS file may be referenced using the @import syntax in the CSS file, and SCSS may also be imported into the referenced CSS file
{
test: /\.css$/,
use: [
!isDev && MiniCssExtractPlugin.loader,
isDev && 'style-loader',
{
loader:"css-loader".options: {importLoaders:1 // The imported files need to be processed by calling sass-loader}},"sass-loader"
].filter(Boolean)},Copy the code
Handling style prefixes
Add style prefixes using postCSs-loader
npm install postcss-loader postcss autoprefixer --save-dev
Copy the code
Add prefixes before working with CSS
{
test: /\.css$/,
use: [
!isDev && MiniCssExtractPlugin.loader,
isDev && 'style-loader',
{
loader:"postcss-loader".options: {plugins: [require('autoprefixer')]}},"postcss-loader"."sass-loader"
].filter(Boolean)},Copy the code
Alternatively, you can create the postCSS configuration file postcss.config.js
module.exports = {
plugins: [require('autoprefixer')]}Copy the code
You can configure the browser compatibility range. Browserslistrc
Cover 99.5%Copy the code
CSS compression
In production we need to compress the CSS file, configure the Minimizer option, and install the compression plugin
npm i optimize-css-assets-webpack-plugin terser-webpack-plugin --save-dev
Copy the code
Configure compression in the webpack.prod.js file
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
optimization:{
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})]
}
Copy the code
File fingerprint
- Hash Hash value of the entire project
- Chunkhash generates a hash value based on the entry
- ContentHash Hash value generated based on the contents of each file
We can reasonably use hash stamps to cache files
! isDev &&new MiniCssExtractPlugin({
filename: "css/[name].[contentHash].css"
})
Copy the code
Processing images
Processing referenced images
import logo from './webpack.png';
let img = document.createElement('img');
img.src = logo;
document.body.appendChild(img);
Copy the code
Using file-loader, the image is packed and the packed path is returned
{
test:/\.jpe?g|png|gif/,
use:{
loader:'file-loader'.options: {name:`img/[name].[ext]`}}}Copy the code
Processing icon
Binary files are also packaged using file-loader
{
test:/woff|ttf|eot|svg|otf/,
use:{
loader:'file-loader'}}Copy the code
Into base64
The url-loader is used to convert the images that meet the requirements into base64. If the url-loader does not meet the requirements, the url-loader automatically invokes file-loader to process the images
{
test:/\.jpe?g|png|gif/,
use:{
loader:'url-loader'.options: {limit: 1.esModule: false.// name:`img/[name].[ext]`,
name: function(file) {
returnfile; }}}}Copy the code
Working with JS modules
willes6
Code compiled intoes5
code
The translation of the code is left to Babel
npm install @babel/core @babel/preset-env babel-loader --save-dev
Copy the code
@babel/core is the core module in Babel, and @babel/preset-env is the set of ES6 to transform ES5 plug-ins. Babel-loader is the bridge between WebPack and Loader.
const sum = (a, b) = > {
return a + b;
};
Copy the code
Add Babel configuration file.babelrc
{
"presets": [["@babel/preset-env"]]}Copy the code
Configure the loader
module: {
rules: [{ test: /\.js$/, use: "babel-loader"}},Copy the code
Packaging now successfully converts ES6 syntax to ES5 syntax!
Parsing decorator
npm i @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators --save-dev
Copy the code
"plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", {"loose":true}]]Copy the code
Legacy: True indicates that the decorator decorator is continued. When loose is false, object.defineProperty is used to define properties
- Plugin will run ahead of Preset
- Plugin will run sequentially starting from the first, Preset is reversed
polyfill
Using @babel/polyfill, modify the configuration as follows:
module.exports = {
entry: ['@babel/polyfill'.'./src/index.js'].module: {
rules: [{
test: /\.jsx? $/,
use: {
loader: 'babel-loader'.options: {
"presets": [["@babel/preset-env",
{
useBuiltIns: "entry"}]],"plugins"}},}]}}Copy the code
No matter what happens, you can import all compatibility packages into the system to support the lower version.
Disadvantages:
- The volume was increased to 470KiB, or 87.2 KiB after compression, up from 345 bytes, an increase of several hundred times.
To optimize the
Fortunately, Babel7 will now support on-demand import. You can reduce the size of compatible packages by simply iterating through your code to find the modules you need to introduce. Thus reducing packaging volume.
Configuration:
"presets": [["@babel/preset-env",
{
// debug:true, // Enable debug
useBuiltIns: "usage".// Import on demand
corejs: {
version: 3.proposals: true
},
targets: { // Support compatible versions
android: '4.2'.ios: '9'}}]Copy the code
Compiled and packaged: 114 KiB in volume and 19.8 KiB in compression. It’s a lot smaller. Isn’t it already perfect!! But there are drawbacks.
Disadvantages: This approach adds methods globally and modifies the prototype directly. This can cause global contamination and overwrite each other if others customize and extend the same method.
@babel/plugin-transform-runtime
This plug-in solves the problem of global contamination.
Change the configuration
"plugins": [['@babel/plugin-transform-runtime', {corejs:3.helpers: true.regenerator: true}]]Copy the code
Code volume: 157 KiB, compressed volume: 26.7 KiB. By comparison, the volume is a little bit larger. So what’s the difference in packaged code? Let’s take a look.
No compiled code for transform-Runtime configured
Configure the compiled code after transform-Runtime
We found transform-Runtime changed all the code we had written. It’s been repackaged so there’s no global contamination.
To compare
volume | Compressed volume | conclusion | |
---|---|---|---|
Use full import, @babel/polyfill | 470KiB | 87.2 KiB | Best not to use |
According to the need to introduce | 114 KiB | 19.8 KiB | It is suitable for project development |
transform-runtime | 157 KiB | 26.7 KiB | This is appropriate when writing a library |
See Resources to understand the Babel configuration
Check the CSS, js
Check js
- eslint
- eslint-loader
- configuring
- babel-eslint
- Rules
- ESlint syntax checks configuration instructions
The standard configuration
- It is recommended to develop the esLint specification for your team
- Improvements based on the ESLint: Recommend configuration
- Turn on as many rules as possible to find code errors
- Helps keep the team’s code style consistent without limiting the development experience
npm install eslint eslint-loader babel-eslint –D
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
enforce: 'pre',
include: [path.resolve(root, 'src')],
options: {
formatter: require('eslint-friendly-formatter'),
fix: true}}Copy the code
Note: eslint-friendly-formatter: indicates a friendly prompt; Enforce: “pre”; This attribute must be added or there will be a problem. The main function of this attribute is to make the loader execute before all loaders execute.
.eslintrc.js
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true,
node: true,
es6: true
},
plugins: [
"html"
],
settings: {
"html/html-extensions": [".html"]."html/indent": "0".// code should start at the beginning of the line (no initial indentation).
"html/indent": "+ 4".// indentation is the <script> indentation plus two spaces.
"html/indent": "tab".// indentation is one tab at the beginning of the line.
"html/report-bad-indent": "error"."html/javascript-mime-types": ["text/javascript"."text/jsx"]
},
extends: ['plugin:vue/recommended', 'eslint:recommended'],
// add your custom rules here
// http://eslint.cn/docs/rules/
// https://cn.eslint.org/docs/user-guide/configuring
rules: {
//vue
"vue/no-use-v-if-with-v-for": 2.// Disallow v-if on the same element as v-for
//un vue
'indent': [2.4, {
'SwitchCase': 2 // The case clause will be indented 4 Spaces relative to the switch statement}].// Enforce consistent indentation
'quotes': [2, 'single', {
'avoidEscape': true,
'allowTemplateLiterals': true}].// Enforces consistent backticks, double quotes, or single quotes
'no-mixed-spaces-and-tabs': 2.// Disallow the combination of space and TAB indentation
'jsx-quotes': [2, 'prefer-single'], // Enforce consistent use of double or single quotes in JSX attributes
'comma-dangle': [2, 'never'], // Require or disallow trailing commas
'no-dupe-keys': 2.Disallow duplicate keys in object literals
'no-eval': 2./ / disable the eval ()
'no-implied-eval': 2.// Disallow methods like eval()
'no-with': 2.// Disable the with statement
'no-redeclare': 2.// Do not declare the same variable more than once
'no-undef': 2.// Disable undeclared variables unless they are mentioned in the /*global */ comment
'no-undef-init': 2.// Disallow initializing variables as undefined
'prefer-const': 2.// Require const to declare variables that are no longer modified after being declared
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0./ / disable the debugger
'no-console': process.env.NODE_ENV === 'production' ? 2 : 0./ / disable the console
//undetermined
"vue/max-attributes-per-line": [2, {
"singleline": 10."multiline": {
"max": 1."allowFirstLine": false}}].// Enforces a maximum number of attributes per row
"vue/singleline-html-element-content-newline": 0.// Line breaks are required before and after the content of the single-line element
"vue/multiline-html-element-content-newline": 0.// Newlines are required before and after the content of multi-line elements
"vue/name-property-casing": [2."PascalCase"].// Enforces a specific case (underscore) for the name attribute in the Vue component
'accessor-pairs': 2.// Forces getters and setters to pair in objects
'arrow-spacing': [1, {
'before': true,
'after': true}].// Forces the arrow function to use consistent Spaces before and after the arrow
'block-spacing': [2, 'always'], // Disallows or enforces Spaces before and after opening and closing parentheses in code blocks
'brace-style': [2, '1tbs', {
'allowSingleLine': true // (default false) allows the opening and closing brackets of a block to be on the same line}].// Enforce a consistent brace style in code blocks
'camelcase': [0, {
'properties': 'always' //(default) Force the attribute name to be hump style}].// Enforce camel spelling naming conventions
'comma-spacing': [2, {
'before': false,
'after': true}].// Enforces consistent Spaces around commas
'comma-style': [2, 'last'], // Enforce a consistent comma style
'constructor-super': 2.// Requires a call to super() in the constructor
'curly': [2, 'multi-line'], // Force all control statements to use the same parenthesis style
'dot-location': [2, 'property'], // Enforces line breaks before and after the dot
'eol-last': 2.// Require or disallow blank lines at the end of the file
'generator-star-spacing': [2, {
'before': true,
'after': true}].// Force a consistent space around the * in generator functions
'handle-callback-err': [0, '^(err|error)$'], // Error tolerance is required in the callback function
'key-spacing': [2, {
'beforeColon': false,
'afterColon': true}].Enforces consistent spacing between keys and values in attributes of object literals
'keyword-spacing': [2, {
'before': true,
'after': true}].// Enforces consistent Spaces around keywords
'new-cap': [2, {
'newIsCap': true.//(default true) requires a function of initial size when calling the new operator
'capIsNew': false // Allows calls to uppercase functions without the new operator}].// Require the constructor to begin with a capital letter
'new-parens': 2.// require parentheses when calling the no-argument constructor
'no-array-constructor': 2.// Disable the Array constructor
'no-caller': 2.// Disable arguments.caller or arguments.callee
'no-class-assign': 2.// Disallow modifying class declared variables
'no-cond-assign': 0.// Disallow assignment operators in conditional expressions
'no-const-assign': 2.// Disallow modifying variables declared by const
'no-control-regex': 2.// Disallow control characters in regular expressions
'no-delete-var': 2.// Disable variable deletion
'no-dupe-args': 2.// Disallow duplicate arguments in function definitions
'no-dupe-class-members': 2.// Disallow duplicate names in class members
'no-duplicate-case': 2.// Disallow duplicate case tags
'no-empty-character-class': 2.// Disallow null character sets in regular expressions
'no-empty-pattern': 2.// Disallow empty destruct mode
'no-ex-assign': 2.// Disallows reassignment of the parameters of the catch clause
'no-extend-native': 2.// Forbid extending native types
'no-extra-bind': 2.// Disallow unnecessary.bind() calls
'no-extra-boolean-cast': 2.// Disable unnecessary Boolean conversions
'no-extra-parens': [2, 'functions'], // Disallow unnecessary parentheses
'no-fallthrough': 2.// Disallow case statements from falling through
'no-floating-decimal': 2.// Disallow leading and trailing decimal points in numeric literals
'no-func-assign': 2.// Disallow reassignment of function declarations
'no-inner-declarations': [2, 'functions'], // Disallow variable or function declarations in nested blocks
'no-invalid-regexp': 2.// Disallow invalid regular expression strings in the RegExp constructor
'no-irregular-whitespace': 2.// Disallow irregular whitespace outside strings and comments
'no-iterator': 2.// Disable the __iterator__ attribute
'no-label-var': 2.// Labels are not allowed to have the same name as variables
'no-labels': [2, {
'allowLoop': false,
'allowSwitch': false}].// Disable label statements
'no-lone-blocks': 2.// Disable unnecessary nesting blocks
'no-multi-spaces': 2.// Disallow multiple Spaces
'no-multi-str': 2.// Disallow multi-line strings
'no-multiple-empty-lines': [2, {
'max': 1}].// Disallow multiple blank lines
'no-global-assign': 2.// Disallow assignment to native or read-only global objects
'no-unsafe-negation': 2.// Disallow the negation operator on the left-hand operand of relational operators
'no-new-object': 2.// Disable the Object constructor
'no-new-require': 2.// Disallow the new operator when calling require
'no-new-symbol': 2.// Disallow the Symbolnew operator from being used with new
'no-new-wrappers': 2.// Disallow the new operator for String, Number, and Boolean
'no-obj-calls': 2.// Disallow calling global objects as functions
'no-octal': 2.// Disable octal literals
'no-octal-escape': 2.// Disallow octal escape sequences in strings
'no-path-concat': 2.// Disallow string concatenation of __dirname and __filename
'no-proto': 2.// Disable the __proto__ attribute
'no-regex-spaces': 2.Disallow multiple Spaces in regular expression literals
'no-return-assign': [2, 'except-parens'], // Disallow assignment statements in return statements
'no-self-assign': 2.// Disallow self-assignment
'no-self-compare': 2.// Disallow self comparison
'no-sequences': 2.// Disable the comma operator
'no-shadow-restricted-names': 2.// Disallow defining identifiers as restricted names
'func-call-spacing': 2.// Requires or disallows Spaces between function identifiers and their calls
'no-sparse-arrays': 2.// Disable sparse arrays
'no-this-before-super': 2.// Disallow this or super before calling super() in constructors
'no-throw-literal': 2.// Disallow throwing exception literals
'no-trailing-spaces': 2.// Disable end-of-line whitespace
'no-unexpected-multiline': 2.// Disallow confusing multi-line expressions
'no-unmodified-loop-condition': 2.// Disable immutable loop conditions
'no-unneeded-ternary': [2, {
'defaultAssignment': false}].// Disallow ternary operators when simpler alternative expressions are available
'no-unreachable': 2.// Disallows unreachable code after return, throw, continue, and break statements
'no-unsafe-finally': 2.// Disallow control flow statements in finally blocks
'no-unused-vars': [2, {
'vars': 'all',
'args': 'none'
}], // Disallow unused variables
'no-useless-call': 2.// Disallow unnecessary.call() and.apply()
'no-useless-computed-key': 2.// Disallow unnecessary computed attributes in objects
'no-useless-constructor': 2.// Disable unnecessary constructors
'no-useless-escape': 0.// Disable unnecessary escape characters
'no-whitespace-before-property': 2.// Disallow whitespace before attributes
'one-var': [2, {
'initialized': 'never'
}], // Forces variables in a function to be declared either together or separately
'operator-linebreak': [2, 'after', { 'overrides': { '? ': 'before', ':': 'before' } }],// Forces operators to use consistent line breaks
'padded-blocks': [2, 'never'], // Requires or disallows in-block padding
'semi': [2, 'always'], Require or disallow semicolons instead of ASI
'semi-spacing': [2, {
'before': false,
'after': true}].// Enforces consistent Spaces before and after semicolons
'space-before-blocks': [2, 'always'], // Enforces consistent whitespace before blocks
'space-before-function-paren': [2, 'never'], // Enforces a consistent space before the opening parenthesis of function
'space-in-parens': [2, 'never'], // Enforces consistent Spaces inside parentheses
'space-infix-ops': 2.// Requires Spaces around the operator
'space-unary-ops': [2, {
'words': true,
'nonwords': false}].// Enforces consistent Spaces around unary operators
'spaced-comment': [2, 'always', {
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
}], // Enforces consistent whitespace in comments
'template-curly-spacing': [2, 'never'], // Requires or disallows the use of whitespace around embedded expressions in template strings
'use-isnan': 2.// Require isNaN() to check NaN
'valid-typeof': 2.// Forces typeof expressions to be compared with valid strings
'wrap-iife': [2, 'any'], // Require IIFE to be enclosed in parentheses
'yield-star-spacing': [2, 'both'], // Enforces whitespace around * in yield* expressions
'yoda': [2, 'never'], // Require or disallow the "Yoda" condition
'object-curly-spacing': [2, 'always', {
objectsInObjects: false}].// Enforces consistent Spaces in braces
'array-bracket-spacing': [2, 'never'] // Enforces consistent Spaces in array square brackets}}Copy the code
CSS validation
stylelint
The installation
npm install –save-dev stylelint stylelint-config-standard
check
npx stylelint “**/*.css”
Used in combination with PostCSS
const fs = require("fs");
const less = require("postcss-less");
const postcss = require("postcss");
// Code to be processed
const code = fs.readFileSync("input.less"."utf8");
postcss([
require("stylelint") ({/* your options */
}),
require("postcss-reporter")({ clearReportedMessages: true })
])
.process(code, {
from: "input.less",
syntax: less
})
.then(() => {})
.catch((err) => console.error(err.stack));
Copy the code
References:
Stylelint postcss plug-in
. Stylelintrc file
{
"extends": "stylelint-config-standard"."plugins": ["stylelint-order"]."rules": {
"order/order": [
"declarations"."custom-properties"."dollar-variables"."rules"."at-rules"]."order/properties-order": [
"position"."z-index"."top"."bottom"."left"."right"."float"."clear"."columns"."columns-width"."columns-count"."column-rule"."column-rule-width"."column-rule-style"."column-rule-color"."column-fill"."column-span"."column-gap"."display"."grid"."grid-template-rows"."grid-template-columns"."grid-template-areas"."grid-auto-rows"."grid-auto-columns"."grid-auto-flow"."grid-column-gap"."grid-row-gap"."grid-template"."grid-template-rows"."grid-template-columns"."grid-template-areas"."grid-gap"."grid-row-gap"."grid-column-gap"."grid-area"."grid-row-start"."grid-row-end"."grid-column-start"."grid-column-end"."grid-column"."grid-column-start"."grid-column-end"."grid-row"."grid-row-start"."grid-row-end"."flex"."flex-grow"."flex-shrink"."flex-basis"."flex-flow"."flex-direction"."flex-wrap"."justify-content"."align-content"."align-items"."align-self"."order"."table-layout"."empty-cells"."caption-side"."border-collapse"."border-spacing"."list-style"."list-style-type"."list-style-position"."list-style-image"."ruby-align"."ruby-merge"."ruby-position"."box-sizing"."width"."min-width"."max-width"."height"."min-height"."max-height"."padding"."padding-top"."padding-right"."padding-bottom"."padding-left"."margin"."margin-top"."margin-right"."margin-bottom"."margin-left"."border"."border-width"."border-top-width"."border-right-width"."border-bottom-width"."border-left-width"."border-style"."border-top-style"."border-right-style"."border-bottom-style"."border-left-style"."border-color"."border-top-color"."border-right-color"."border-bottom-color"."border-left-color"."border-image"."border-image-source"."border-image-slice"."border-image-width"."border-image-outset"."border-image-repeat"."border-top"."border-top-width"."border-top-style"."border-top-color"."border-top"."border-right-width"."border-right-style"."border-right-color"."border-bottom"."border-bottom-width"."border-bottom-style"."border-bottom-color"."border-left"."border-left-width"."border-left-style"."border-left-color"."border-radius"."border-top-right-radius"."border-bottom-right-radius"."border-bottom-left-radius"."border-top-left-radius"."outline"."outline-width"."outline-color"."outline-style"."outline-offset"."overflow"."overflow-x"."overflow-y"."resize"."visibility"."font"."font-style"."font-variant"."font-weight"."font-stretch"."font-size"."font-family"."font-synthesis"."font-size-adjust"."font-kerning"."line-height"."text-align"."text-align-last"."vertical-align"."text-overflow"."text-justify"."text-transform"."text-indent"."text-emphasis"."text-emphasis-style"."text-emphasis-color"."text-emphasis-position"."text-decoration"."text-decoration-color"."text-decoration-style"."text-decoration-line"."text-underline-position"."text-shadow"."white-space"."overflow-wrap"."word-wrap"."word-break"."line-break"."hyphens"."letter-spacing"."word-spacing"."quotes"."tab-size"."orphans"."writing-mode"."text-combine-upright"."unicode-bidi"."text-orientation"."direction"."text-rendering"."font-feature-settings"."font-language-override"."image-rendering"."image-orientation"."image-resolution"."shape-image-threshold"."shape-outside"."shape-margin"."color"."background"."background-image"."background-position"."background-size"."background-repeat"."background-origin"."background-clip"."background-attachment"."background-color"."background-blend-mode"."isolation"."clip-path"."mask"."mask-image"."mask-mode"."mask-position"."mask-size"."mask-repeat"."mask-origin"."mask-clip"."mask-composite"."mask-type"."filter"."box-shadow"."opacity"."transform-style"."transform"."transform-box"."transform-origin"."perspective"."perspective-origin"."backface-visibility"."transition"."transition-property"."transition-duration"."transition-timing-function"."transition-delay"."animation"."animation-name"."animation-duration"."animation-timing-function"."animation-delay"."animation-iteration-count"."animation-direction"."animation-fill-mode"."animation-play-state"."scroll-behavior"."scroll-snap-type"."scroll-snap-destination"."scroll-snap-coordinate"."cursor"."touch-action"."caret-color"."ime-mode"."object-fit"."object-position"."content"."counter-reset"."counter-increment"."will-change"."pointer-events"."all"."page-break-before"."page-break-after"."page-break-inside"."widows"]."no-empty-source": null."property-no-vendor-prefix": [true, {"ignoreProperties": ["background-clip"."box-orient"]}],
"number-leading-zero": "never"."number-no-trailing-zeros": true."length-zero-no-unit": true."property-no-unknown": [true, {"ignoreProperties": ["box-orient"]}],
"value-list-comma-space-after": "always"."declaration-colon-space-after": "always"."value-list-max-empty-lines": 0."shorthand-property-no-redundant-values": true."declaration-block-no-duplicate-properties": true."declaration-block-no-redundant-longhand-properties": true."declaration-block-semicolon-newline-after": "always"."block-closing-brace-newline-after": "always"."media-feature-colon-space-after": "always"."media-feature-range-operator-space-after": "always"."at-rule-name-space-after": "always"."indentation": 4."no-eol-whitespace": true."string-no-newline": null}}Copy the code
Vue compilation is supported
const { VueLoaderPlugin } = require('vue-loader');
{
test: /\.vue$/,
use: [
'cache-loader',
{
loader: 'vue-loader',
options: {
// other vue-loader options go here
}
}
]
}
plugins:[new VueLoaderPlugin()]
Copy the code
Configure the TS development ring
Use ts – loader
To use the TS, you need to install the TS-related configuration
npm install typescript ts-loader --save-dev
Copy the code
Generate the TS configuration file
npx tsc --init
Copy the code
Configuration ts – loader
{
test:/\.tsx? /,
use: ['ts-loader'].exclude: /node_modules/
}
Copy the code
Change the import file to ts file
let a:string = 'hello';
console.log(a);
Copy the code
NPM run dev: Ts file parsed properly.
Use the preset – typescript
You don’t need typescript
npm install @babel/preset-typescript
Copy the code
{
"presets": [["@babel/preset-env", {"useBuiltIns":"usage"."corejs":2}]."@babel/preset-react"["@babel/preset-typescript", {"allExtensions": true}]],"plugins": [["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", {"loose":true}]."@babel/plugin-transform-runtime"]}Copy the code
Configure the TS and React environment
Install the React module
npm i @babel/preset-react --save-dev # Parse JSX syntax
npm i react @types/react @types/react-dom react react-dom typescript
Copy the code
import React from 'react';
import ReactDOM from 'react-dom';
const state = {number:0};
type State = Readonly<typeof state>;
class Counter extends React.Component<object.State>{
state:State = state
handleClick =() = >{
this.setState({number:this.state.number+1})}render(){
const {number} = this.state;
return (
<div>
<button onClick={this.handleClick}>Click on the</button>
{number}
</div>
)
}
}
ReactDOM.render(<Counter></Counter>.document.getElementById('root'));
Copy the code
Configure the TS + VUE environment
Install the modules required by vUE
npm install vue-loader vue-template-compiler --save-dev
npm install vue vue-property-decorator
Copy the code
Configuration ts – loader
{
test: /\.tsx? /,
use: {
loader:'ts-loader'.options: {
appendTsSuffixTo: [/\.vue$/],}},exclude: /node_modules/
}
Copy the code
Use vue-loader plug-in
const VueLoaderPlugin = require('vue-loader/lib/plugin');
new VueLoaderPlugin();
Copy the code
Configure parsing. Vue files
{
test:/\.vue$/,
use:'vue-loader'
}
Copy the code
Added vue-shims.d.ts to recognize. Vue files
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
Copy the code
Index. The TSX composite file
import Vue from 'vue';
import App from './App.vue';
let vm = new Vue({
render:h= >h(App)
}).$mount('#root')
Copy the code
App. Vue file
<template>
<div>
<div v-for="(todo,index) in todos" :key="index">{{todo}}</div>
</div>
</template>
<script lang="ts">
import {Component,Vue} from 'vue-property-decorator';
@Component
export default class Todo extends Vue{
public todos = ['banana'.'apple'.'orange']}</script>
Copy the code
Common plugin
const CopyWebpackPlugin = require('copy-webpack-plugin'); / / copy
const HappyPack = require('happypack'); // Multi-process running
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');/ / CSS compression
const TerserPlugin = require('terser-webpack-plugin');
const happyThreadPool = HappyPack.ThreadPool({
size: os.cpus().length
});
rules:[
{
test: /\.(j|t)sx?$/,
use: 'happypack/loader?id=happy-babel-js' // Add new HappyPack build loader
}
],
plugins: [
new CopyWebpackPlugin([
{
from: './src/common',
to: './common'
}
]),
new HappyPack({
id: 'happy-babel-js',
loaders: [
'cache-loader',
{
loader: 'babel-loader'
}
],
threadPool: happyThreadPool
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
aaa: JSON.stringify({
version: 'version',
})
}),
new OptimizeCssAssetsPlugin(),
new webpack.HashedModuleIdsPlugin({
hashDigest: 'hex'
}),
new webpack.NamedChunksPlugin((chunk) => {
if (chunk.name) {
return chunk.name;
}
const hash = require('hash-sum');
const joinedHash = hash(
Array.from(chunk.modulesIterable, (m) => m.id).join('_')
);
return `chunk-` + joinedHash;
})
],
optimization: {
minimize: true,
minimizer: [new TerserPlugin({
extractComments: false,
terserOptions: {
output: {
comments: false
},
cache: true.// Enable caching
parallel: true.// Enable multi-threaded compression
compress: { / / configuration
// It is necessary to open it
warnings: true.// Turn off warnings: Display warnings when deleting unreachable code or unused declarations, etc
drop_console: true,
drop_debugger: true}}}})]Copy the code
source map
- Sourcemap is a technology designed to help us debug the original development code when it is inconsistent with the actual running code
- Webpack can be configured to give us automatically
source maps
File,map
A file is a method that corresponds to a compiled file and a source file - whyeval
- source-map
- Javascript_source_map algorithm
type | meaning |
---|---|
source-map | The sourcemap quality of the best raw code has complete results, but is slow |
eval-source-map | The original code is the same, but of the highest quality and lowest performance |
cheap-module-eval-source-map | The original code (inline only) does the same, but with higher quality and lower performance |
cheap-eval-source-map | The conversion code (inline) is executed by EVAL for each module, and sourcemap acts as a dataURL for Eval |
eval | Generated code is eval for each module, and @sourceURL exists. Build mode with EVAL can cache SourceMap |
cheap-source-map | The sourcemap generated by the conversion code (inline) has no column mapping, and the Sourcemap generated from loaders is not used |
cheap-module-source-map | The original code (inline only) is the same as above except for each line characteristic mapped from the Loader |
What looks like a lot of configuration items are just any combination of the five keywords eval, source-map, cheap, module, and inline
The keyword | meaning |
---|---|
eval | Wrap module code in eval |
source-map | Generate the.map file |
cheap | Contains no column information (more on column information below) and no Sourcemap for the Loader |
module | Include loader’s sourcemap (such as JSX to JS, Babel’s sourcemap), otherwise the source file cannot be defined |
inline | Embed.map as a DataURI without generating a separate.map file |
- The eval eval perform
- The eval – source – generate sourcemap map
- Cheap-module-eval-source-map does not contain columns
- Cheap -eval-source-map cannot see the actual source code
Devtool :”cheap-module-eval-source-map”,// development environment configuration
reference
Reference documentation
- webpack-start
- resolve
List of Common Loaders
- Webpack can use loader to preprocess files. This allows you to package any static resources other than JavaScript. You can easily write your own loader using Node.js.
- awesome-loaders
file
- Raw -loader Load file raw content (UTF-8)
- Val-loader executes the code as a module and exports to JS code
- Url-loader works like a file loader, but returns a data URL if the file is smaller than the limit
- File-loader sends the file to the output folder and returns the (relative) URL
JSON
- Json-loader loads JSON files (default included)
- Json5-loader loads and translates JSON 5 files
- Cson -loader loads and translates Cson files
Transpiling
- Script-loader executes a JavaScript file (such as in a script tag) once in a global context, without parsing
- Babel-loader loads the ES2015+ code and then translates it to ES5 using Babel
- Buble-loader uses buble to load ES2015+ code and translate the code to ES5
- Traceur – Loader loads the ES2015+ code and then translates it into ES5 using traceur
- Ts-loader or awesome-typescript-loader loads typescript 2.0+ like JavaScript
- Coffee-loader loads CoffeeScript like JavaScript
Template (Templating)
- Html-loader exports HTML as a string and references static resources
- Pug-loader loads the PUg template and returns a function
- Jade-loader loads the Jade template and returns a function
- Markdown-loader translates markdown to HTML
- React-markdown-loader compiles markdown into the React component using markdown-parse parser
- Posthtml -loader uses PosthTML to load and convert HTML files
- Handlebars -loader transfers handlebars to HTML
- Markup -inline-loader converts an inline SVG/MathML file to HTML. Useful when applying icon fonts, or CSS animations to SVG
style
- Style-loader adds the module’s export to the DOM as a style
- Css-loader parses the CSS file, loads it using import, and returns the CSS code
- Less-loader loads and translates less files
- Sass -loader loads and translates SASS/SCSS files
- Postcss-loader Loads and translates CSS/SSS files using postCSS
- Stylus – Loader loads and translates stylus files
Linting && Testing
- Mocha – Loader using Mocha tests (browser /NodeJS)
- Eslint-loader PreLoader, which uses esLint to clean code
- Jshint-loader PreLoader: uses jshint to clear codes
- Jscs-loader PreLoader: uses JSCS to check code styles
- Coverjs-loader PreLoader, which uses CoverJS to determine test coverage
Framework (Frameworks)
- Vue-loader loads and translates VUE components
- Polymer-loader is processed using a selective preprocessor and requires () Web components similar to first-class modules
- Angular2-template-loader loads and translates Angular components