安裝 node.js
當前 node.js 版本 :v12.13.1
當前 npm 版本 : 6.12.1javascript
完整源碼css
喜歡就加個星吧html
mkdir webpack4-react && cd webpack4-react npm init -y
當前 webpack 版本:4.41.5
當前 webpack-cli 版本:3.3.10java
npm install --save-dev webpack webpack-cli
或node
yarn add webpack webpack-cli --dev
調整 package.json 文件,以便確保咱們安裝包是私有的(private),而且移除 main 入口。這能夠防止意外發布你的代碼。
package.jsonreact
{ ... "description": "webpack4-react", "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, ... }
npm install --save lodash
或webpack
yarn add lodash
webpack4-react |- package.json |- /dist |- index.html |- /src |- index.js
package.jsongit
{ "name": "webpack4-react", "version": "1.0.0", "description": "webpack4-react", "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "lodash": "^4.17.15" }, "devDependencies": { "webpack": "^4.41.5", "webpack-cli": "^3.3.10" } }
dist/index.htmles6
<!DOCTYPE html> <html> <head> <title>webpack4-react</title> </head> <body> <script src="main.js"></script> </body> </html>
src/index.jsgithub
import _ from 'lodash'; function component() { var element = document.createElement('div'); element.innerHTML = _.join(['Hello', 'webpack'], ' '); return element; } document.body.appendChild(component());
npx webpack
將看到如下輸出:
Hash: 17a14a12467064d9d4dd Version: webpack 4.41.5 Time: 1239ms Built at: 2020-01-04 10:56:16 Asset Size Chunks Chunk Names main.js 72.1 KiB 0 [emitted] main Entrypoint main = main.js [1] ./src/index.js 210 bytes {0} [built] [2] (webpack)/buildin/global.js 472 bytes {0} [built] [3] (webpack)/buildin/module.js 497 bytes {0} [built] + 1 hidden module
此時在 dist 文件夾下已經生成一個 main.js 文件
在瀏覽器中打開 dist下的index.html,若是一切訪問都正常,你應該能看到如下文本:'Hello webpack'。
簡易打包已經完成
webpack4-react |- package.json |- webpack.config.js |- /dist |- index.html |- /src |- index.js
webpack.config.js
const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') } };
dist/index.html
... <body> <script src="bundle.js"></script> </body> ...
package.json
{ "name": "webpack4-react", "version": "1.0.0", "description": "webpack4-react", "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "lodash": "^4.17.15" }, "devDependencies": { "webpack": "^4.41.5", "webpack-cli": "^3.3.10" } }
npm run build
終端將輸出:
Hash: 9cbb2fac6cc224bfe661 Version: webpack 4.41.5 Time: 1272ms Built at: 2020-01-04 11:39:26 Asset Size Chunks Chunk Names main.js 72.1 KiB 0 [emitted] main Entrypoint main = main.js [1] ./src/index.js 213 bytes {0} [built] [2] (webpack)/buildin/global.js 472 bytes {0} [built] [3] (webpack)/buildin/module.js 497 bytes {0} [built] + 1 hidden module
一樣的, dist 文件夾下生成bundle.js文件
這樣就實現了基本的webpack構建了
npm install --save-dev react react-dom
npm install --save-dev @babel/cli @babel/core @babel/preset-react @babel/preset-env @babel/plugin-transform-runtime babel-loader
src/index.js
import React from 'react'; import ReactDom from 'react-dom'; const hello = 'Hello React' ReactDom.render( <div> <div>{hello}</div> </div>, document.getElementById('app'), );
dist/index.html
... <body> <div id="app"></div> <script src="bundle.js"></script> </body> ...
爲了使用babel解析 jsx
webpack.config.js
... entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: [ { loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { useBuiltIns: 'usage', corejs: 3, targets: { chrome: '58', ie: '8', }, }, ], '@babel/preset-react', ], }, }, ], }, ], } ...
在根目錄下新建 .babelrc 文件
.babelrc
{ "presets": [ [ "@babel/preset-env", { "useBuiltIns": "usage", "corejs": 3, "targets": { "chrome": "58", "ie": "8" } } ], "@babel/preset-react" ], "plugins": [ [ "@babel/plugin-transform-runtime", { "absoluteRuntime": false, "corejs": false, "helpers": true, "regenerator": true, "useESModules": false } ] ] }
當前文件目錄結構:
webpack4-react |- /dist |- index.html |- /src |- index.js |- .babelrc |- package.json |- webpack.config.js
執行 npm run build 終端輸出: ``` $ webpack Hash: f4d46dd4732764195f93 Version: webpack 4.41.5 Time: 446ms Built at: 2020-01-04 13:28:48 Asset Size Chunks Chunk Names bundle.js 128 KiB 0 [emitted] main Entrypoint main = bundle.js [3] ./src/index.js 211 bytes {0} [built] + 7 hidden modules ```
在瀏覽器中打開 dist下的index.html,若是一切訪問都正常,你應該能看到如下文本:'Hello React'。
npm install --save-dev webpack-dev-server
webpack.config.js
... entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') }, devServer: { contentBase: '/src', hot: true, }, ...
npm install --save-dev html-webpack-plugin
webpack.config.js
... devServer: { contentBase: '/src', hot: true, }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', filename: './index.html', chunks: ['index'], inject: 'body', }), ], ...
package.json
{ "name": "webpack4-react", "version": "1.0.0", "description": "webpack4-react", "private": true, "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack-dev-server --open --config webpack.config.js", "build": "webpack --config webpack.config.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "lodash": "^4.17.15", "react": "^16.12.0", "react-dom": "^16.12.0" }, "devDependencies": { "@babel/cli": "^7.7.7", "@babel/core": "^7.7.7", "@babel/plugin-transform-runtime": "^7.7.6", "@babel/preset-env": "^7.7.7", "@babel/preset-react": "^7.7.4", "babel-loader": "^8.0.6", "html-webpack-plugin": "^3.2.0", "webpack": "^4.41.5", "webpack-cli": "^3.3.10", "webpack-dev-server": "^3.10.1" } }
npm run dev
執行
npm run dev
後會自動打開瀏覽器,此時修改 index.js 文件中內容,瀏覽器會實時更新
刪除dist文件夾
執行 npm run build 打包依舊會在dist下生成打包文件
爲了從 JavaScript 模塊中 import 一個 CSS 文件,你須要在 module 配置中 安裝並添加 style-loader 和 css-loader:
npm install --save-dev style-loader css-loader
module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader', ] }, ... }
import './style/reset.css';
執行 npm run dev
,會看到 reset.css 中的樣式已經生效
下載依賴
npm install --save-dev autoprefixer postcss-loader npm install --save-dev less-loader node-sass sass sass-loader
這個過程當中安裝 node-sass 可能會很慢, 耐心等待
建立React組件
建立以下目錄文件及內容:
webpack4-react |- src |- components |- Date |- index.jsx |- style.scss |- style |- reset.scss |- index.js |- .babelrc |- package.json |- webpack.config.js
src/components/Date/index.jsx
import React from 'react'; import style from './style.scss'; class DateComponent extends React.Component { constructor(props) { super(props); this.state = { date: new Date(), }; } componentDidMount() { this.timerID = setInterval(() => this.tick(), 1000); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date(), }); } render() { const { date } = this.state; return ( <div> <div className={style.title}>時間</div> <div className={style.title}> {date.toLocaleTimeString()} </div> </div> ); } } export default DateComponent;
src/components/Date/style.scss
.title { height: 50px; font: bold 20px '微軟雅黑'; text-align: center; color: #000; }
引入組件
src/index.js
import React from 'react'; import ReactDom from 'react-dom'; import DateComponents from './components/Date/index.jsx'; import './style/reset.scss'; const hello = 'Hello React'; ReactDom.render( <div> <div>{hello}</div> <DateComponents /> </div>, document.getElementById('app') );
新增 CSS 相關的 webpack 配置
根目錄下新建 tools/utils.js
// css 配置 const styleLoader = { loader: 'style-loader', }; const cssLoader = { loader: 'css-loader', options: { modules: true, // webpack3 爲 module sourceMap: true, importLoaders: 2, }, }; const postCssLoader = { loader: 'postcss-loader', }; const sassLoader = { loader: 'sass-loader', options: { sourceMap: true, }, }; const lessLoader = { loader: 'less-loader', }; exports.loadersConfig = { styleLoader, cssLoader, postCssLoader, sassLoader, lessLoader, }; // css 配置
webpack.config.js
... const utils = require('./tools/utils.js'); const { postCssLoader, styleLoader, sassLoader, cssLoader, } = utils.loadersConfig; ... module.exports = { ... module: { rules: [ { test: /\.css$/, exclude: /node_modules/, use: [styleLoader, cssLoader, postCssLoader], }, { test: /\.scss$/, include: [/pages/, /components/, /style/], use: [ styleLoader, cssLoader, postCssLoader, sassLoader, ], }, } ... };
新增 postcss-loader 配置文件
根目錄下新增 postcss.config.js
const AUTOPREFIXER_BROWSERS = [ 'Android 2.3', 'Android >= 4', 'Chrome >= 35', 'Firefox >= 31', 'Explorer >= 8', 'iOS >= 7', 'Opera >= 12', 'Safari >= 7.1', ]; module.exports = { plugins: [require('autoprefixer')({overrideBrowserslist: ['> 0.15% in CN']})], };
這時候執行
npm run dev
命令會報錯,由於缺乏一些babel依賴,下載一下就行了
npm install --save @babel/runtime core-js
執行 npm run dev
,自動打開瀏覽器,css 相關的配置構建完成
npm install --save-dev file-loader url-loader
... module: { rules: [ ... { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use: [ { loader: 'url-loader', options: { name: '[path][name].[ext]', limit: 1024 * 15, fallback: 'file-loader', }, }, ], }, ... ] } ...
src/components/Date/index.jsx
... import reactLogo from './../../images/React.svg'; import webpackLogo from './../../images/webpack.svg'; ... render() { const { date } = this.state; return ( <div> <div className={style.title}>時間</div> <div> <img className={style.logo} src={reactLogo} alt="" /> <img className={style.logo} src={webpackLogo} alt="" /> </div> <div className={style.title}> {date.toLocaleTimeString()} </div> </div> ); } ...
字體、數據等參考 webpack 官網 資源管理
在代碼引入組件或圖片時,咱們來配置一些便捷的方式
webpack.config.js
// 引入 node 的 path 模塊 const path = require('path'); ... module.exports = { ... resolve: { // 設置模塊導入規則,import/require時會直接在這些目錄找文件 modules: ['node_modules'], // import導入時省略後綴 extensions: ['.js', '.jsx', '.scss', '.less', '.css', '.json'], // import導入時別名 alias: { '@components': path.resolve('./src/components'), '@images': path.resolve('./src/images'), '@style': path.resolve('./src/style'), }, }, ... }
舉個🌰
src/index.js 中
import React from 'react'; import ReactDom from 'react-dom'; import DateComponents from '@components/Date/index.jsx'; import '@style/reset.scss'; const hello = 'Hello React'; ReactDom.render( <div> <div>{hello}</div> <DateComponents /> </div>, document.getElementById('app') );
此時 執行 npm run dev
查看
開發環境(development)和生產環境(production)的構建目標差別很大。在開發環境中,咱們須要具備強大的、具備實時從新加載(live reloading)或熱模塊替換(hot module replacement)能力的 source map 和 localhost server。而在生產環境中,咱們的目標則轉向於關注更小的 bundle,更輕量的 source map,以及更優化的資源,以改善加載時間。因爲要遵循邏輯分離,咱們一般建議爲每一個環境編寫彼此獨立的 webpack 配置。
webpack-merge
配置npm install --save-dev webpack-merge clean-webpack-plugin uglifyjs-webpack-plugin
根目錄下建立 webpack 文件夾
|- webpack |- webpack.common.js |- webpack.dev.js |- webpack.production.js
webpack.common.js
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const utils = require('./../tools/utils'); const { postCssLoader, styleLoader, sassLoader, cssLoader } = utils.loadersConfig; module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, '../dist'), }, devServer: { contentBase: '/src', hot: true, }, resolve: { // 設置模塊導入規則,import/require時會直接在這些目錄找文件 modules: ['node_modules'], // import導入時省略後綴 extensions: ['.js', '.jsx', '.scss', '.less', '.css', '.json'], // import導入時別名 alias: { '@assets': path.resolve('./src/assets'), '@common': path.resolve('./src/common'), '@components': path.resolve('./src/components'), '@images': path.resolve('./src/images'), '@pages': path.resolve('./src/pages'), '@style': path.resolve('./src/style'), }, }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', filename: './index.html', chunks: ['index'], inject: 'body', }), ], module: { rules: [ { test: /\.css$/, exclude: /node_modules/, use: [styleLoader, cssLoader, postCssLoader], }, { test: /\.scss$/, include: [/pages/, /components/, /style/], use: [styleLoader, cssLoader, postCssLoader, sassLoader], }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use: [ { loader: 'url-loader', options: { name: '[path][name].[ext]', limit: 1024 * 15, fallback: 'file-loader', }, }, ], }, { test: /\.(js|jsx)$/, exclude: /node_modules/, use: [ { loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { useBuiltIns: 'usage', corejs: 3, targets: { chrome: '58', ie: '8', }, }, ], '@babel/preset-react', ], }, }, ], }, ], }, };
webpack.dev.js
const merge = require('webpack-merge'); const common = require('./webpack.common.js'); module.exports = merge(common, { mode: 'development', devtool: 'inline-source-map', devServer: { contentBase: '/src', hot: true, } }); webpack.production.js
const merge = require('webpack-merge'); const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); // 用來縮小(壓縮優化)js文件 const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const common = require('./webpack.common.js'); module.exports = merge(common, { mode: 'production', devtool: 'source-map', plugins: [ new UglifyJSPlugin({ sourceMap: true, }), new CleanWebpackPlugin(), ], });
package.json
"dev": "webpack-dev-server --open --config webpack/webpack.dev.js", "build": "webpack --config webpack/webpack.production.js"
下載依賴
npm install --save-dev cross-env
npm 腳本命令更改
"dev": "cross-env NODE_ENV=development webpack-dev-server --open --config webpack/webpack.dev.js", "build": "cross-env NODE_ENV=production webpack --config webpack/webpack.production.js"
在 npm 腳本執行的時候設置的環境變量經過 process.env.NODE_ENV 來獲取,process.env.NODE_ENV 的值 在當前腳本下有兩種: development , production , 藉此能夠根據不一樣環境設置不一樣的配置。
npm install --save-dev html-loader
webpack.config.common.js
... entry: { //配置頁面入口 index: ['./src/index.js'], }, output: { //配置輸出選項 path: path.resolve(__dirname, '../dist'), //輸出路徑爲,當前路徑下 filename: '[name].[hash:5].js', //輸出後的文件名稱 }, ... plugins: [ new HtmlWebpackPlugin({ title: 'webpack & react', template: './src/index.html', //本地模板文件的位置,支持加載器(如handlebars、ejs、undersore、html等),如好比 handlebars!src/index.hbs; filename: './index.html', //輸出文件的文件名稱,默認爲index.html,不配置就是該文件名;此外,還能夠爲輸出文件指定目錄位置(例如'html/index.html') chunks: ['index'], // chunks主要用於多入口文件,當你有多個入口文件,那就回編譯後生成多個打包後的文件,那麼chunks 就能選擇你要使用那些js文件 inject: 'body', //一、true或者body:全部JavaScript資源插入到body元素的底部二、head: 全部JavaScript資源插入到head元素中三、false: 全部靜態資源css和JavaScript都不會注入到模板文件中 showErrors: true, //是否將錯誤信息輸出到html頁面中 hash: false, //是否爲全部注入的靜態資源添加webpack每次編譯產生的惟一hash值 favicon: 'react.ico', //添加特定的 favicon 路徑到輸出的 HTML 文件中。 minify: { //是否對大小寫敏感,默認false caseSensitive: true, //是否簡寫boolean格式的屬性如:disabled="disabled" 簡寫爲disabled 默認false collapseBooleanAttributes: true, //是否去除空格,默認false collapseWhitespace: true, //是否壓縮html裏的css(使用clean-css進行的壓縮) 默認值false; minifyCSS: true, //是否壓縮html裏的js(使用uglify-js進行的壓縮) minifyJS: true, //Prevents the escaping of the values of attributes preventAttributesEscaping: true, //是否移除屬性的引號 默認false removeAttributeQuotes: true, //是否移除註釋 默認false removeComments: true, //從腳本和樣式刪除的註釋 默認false removeCommentsFromCDATA: true, //是否刪除空屬性,默認false removeEmptyAttributes: true, // 若開啓此項,生成的html中沒有 body 和 head,html也未閉合 removeOptionalTags: false, //刪除多餘的屬性 removeRedundantAttributes: true, //刪除script的類型屬性,在h5下面script的type默認值:text/javascript 默認值false removeScriptTypeAttributes: true, //刪除style的類型屬性, type="text/css" 同上 removeStyleLinkTypeAttributes: true, //使用短的文檔類型,默認false useShortDoctype: true, }, }), ] ... module: { rules: [ test: /\.html$/, use: 'html-loader', ] } npm install --save-dev html-loader
npm install --save-dev mini-css-extract-plugin
webpack.config.common.js
... const devMode = process.env.NODE_ENV !== 'production'; const MiniCssExtractPlugin = require('mini-css-extract-plugin'); ... module.exports = { ... plugins: [ ... new MiniCssExtractPlugin({ filename: devMode ? '[name].css' : '[name]_[hash:5].css', chunkFilename: devMode ? '[id].css' : '[id]_[hash:5].css', disable: false, //是否禁用此插件 allChunks: true, }), ... ] ... module: { ... { test: /\.scss$/, include: [/pages/, /components/, /style/], use: [ devMode ? styleLoader : MiniCssExtractPlugin.loader, cssLoader, postCssLoader, sassLoader, ], }, ... } }
npm install --save-dev uglifyjs-webpack-plugin clean-webpack-plugin
webpack.production.js
... const merge = require('webpack-merge'); const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const common = require('./webpack.config.common.js'); module.exports = merge(common, { mode: 'production', devtool: 'source-map', plugins: [ new UglifyJSPlugin({ sourceMap: true, }), new CleanWebpackPlugin(), ], }); ...
npm install --save-dev happypack
webpack.config.common.js
... const os = require('os'); const HappyPack = require('happypack'); const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }); ... plugins: [ ... new HappyPack({ id: 'babel', //用id來標識 happypack處理那裏類文件 threadPool: happyThreadPool, //共享進程池 loaders: [ { loader: 'babel-loader', }, ], }), ... ], ... module: { rules: [ { test: /\.(js|jsx)$/, use: ['happypack/loader?id=babel'], exclude: /node_modules/, //設置node_modules裏的js文件不用解析 }, ] } ...
npm install --save-dev @babel/polyfill @babel/plugin-transform-arrow-functions @babel/preset-es2017
webpack.common.js
entry: { //配置頁面入口 index: ['@babel/polyfill', './src/index.js'], },
vs code 格式化插件 使用的是 Prettier - Code formatter
以及 ESLint
|- .vscode |- setting.json
setting.json
{ "editor.tabSize": 4, "prettier.singleQuote": true, "editor.detectIndentation": false, "editor.renderControlCharacters": true, "editor.renderWhitespace": "all", "emmet.includeLanguages": { "javascript": "javascriptreact" }, "prettier.trailingComma": "es5", "emmet.triggerExpansionOnTab": true, "javascript.implicitProjectConfig.experimentalDecorators": true, "workbench.colorTheme": "Solarized Light", "window.zoomLevel": 0, "prettier.useTabs": true, "editor.foldingStrategy": "indentation", "explorer.confirmDelete": false, "javascript.updateImportsOnFileMove.enabled": "never", "eslint.validate": [ { "language": "javascript", "autoFix": true }, { "language": "javascriptreact", "autoFix": true } ], "eslint.autoFixOnSave": true }
npm insatll --save-dev babel-eslint eslint eslint-config-airbnb eslint-config-react-app eslint-friendly-formatter eslint-loader eslint-plugin-flowtype eslint-plugin-html eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react autoprefixer pre-commit
根目錄下新建 .eslintrc.js 文件
module.exports = { root: true, env: { browser: true, commonjs: true, es6: true, }, extends: [ 'airbnb', ], globals: { $: true, process: true, __dirname: true, }, parser: 'babel-eslint', parserOptions: { //es6的module模式 sourceType: 'module', ecmaFeatures: { experimentalObjectRestSpread: true, jsx: true, }, ecmaVersion: 9, }, settings: { 'import/ignore': ['node_modules', '.s?css', '@w*'], }, // "excludedFiles": "*.test.js", plugins: ['react', 'import', 'jsx-a11y'], rules: { 'import/no-unresolved': 0, 'import/extensions': 0, 'import/prefer-default-export': 0, 'react/prop-types': 0, 'react/jsx-filename-extension': 0, 'react/prefer-stateless-function': 0, 'react/jsx-indent': [2, 'tab'], 'react/jsx-indent-props': [2, 'tab'], 'react/require-default-props': 0, // // @off 同構應用須要在 didMount 裏寫 setState 'react/no-did-mount-set-state': 0, 'jsx-a11y/anchor-is-valid': 0, 'jsx-a11y/click-events-have-key-events': 0, 'jsx-a11y/mouse-events-have-key-events': 0, 'jsx-a11y/no-noninteractive-element-interactions': 0, 'jsx-a11y/no-static-element-interactions': 0, 'no-return-assign': 0, 'no-console': 0, // 0、一、2分別表示不開啓檢查、警告、錯誤 indent: [2, 'tab', { SwitchCase: 1 }], // tab縮進 // 圈複雜度 complexity: [2, 9], 'max-params': [2, 7], 'max-depth': [2, 4], 'max-len': [ 'error', { code: 150, tabWidth: 4, ignoreComments: true, ignoreUrls: true, ignoreStrings: true, ignoreTemplateLiterals: true, ignoreRegExpLiterals: true, }, ], 'no-tabs': 0, 'object-curly-newline': [ 0, { ObjectExpression: 'always', ObjectPattern: { multiline: true }, ImportDeclaration: 'never', ExportDeclaration: { multiline: true, }, }, ], 'object-curly-spacing': 0, 'arrow-parens': [2, 'as-needed'], // 最大回調層數 'max-nested-callbacks': [2, 3], 'no-unused-vars': [ 2, { argsIgnorePattern: '^React', varsIgnorePattern: '[Rr]eact|[Ss]tyle', }, ], 'no-extra-boolean-cast': 0, 'array-callback-return': 0, 'no-param-reassign': 0, 'jsx-quotes': [0, 'prefer-double'], //強制在JSX屬性(jsx-quotes)中一導致用雙引號 'no-underscore-dangle': 0, 'quote-props': 0, // "no-native-reassign": 2,//不能重寫native對象 // // if while function 後面的{必須與if在同一行,java風格。 // "brace-style": [2, "1tbs", { "allowSingleLine": true }], // // 雙峯駝命名格式 // "camelcase": 2, // // 以方括號取對象屬性時,[ 後面和 ] 前面是否須要空格, 可選參數 never, always // "computed-property-spacing": [2,"never"], // //容許箭頭函數能夠省略小括號 // 'arrow-parens': 0, // 'no-extra-semi': 2, // 不容許多餘的分號 // //容許使用async-await函數 // 'generator-star-spacing': 0, // //在開發環境開啓debugger功能,生產環境禁止使用debugger // 'no-debugger': process.env.NODE_ENV === 'development' ? 0 : 2, // "quotes": [2, "single"], //單引號 // "no-var": 2, //對var警告 // "semi": ["error", "always"], //不強制使用分號 // "no-irregular-whitespace": 0, //不規則的空白不容許 // "no-alert": 2, //禁止使用alert confirm prompt // "no-lone-blocks": 0, //禁止沒必要要的嵌套塊 // "no-class-assign": 2, //禁止給類賦值 // "no-cond-assign": 2, //禁止在條件表達式中使用賦值語句 // "no-const-assign": 2, //禁止修改const聲明的變量 // "no-delete-var": 2, //不能對var聲明的變量使用delete操做符 // "no-dupe-keys": 2, //在建立對象字面量時不容許鍵重複 // "no-duplicate-case": 2, //switch中的case標籤不能重複 // "no-dupe-args": 2, //函數參數不能重複 // "no-empty": 2, //塊語句中的內容不能爲空 // "no-func-assign": 2, //禁止重複的函數聲明 // "no-invalid-this": 0, //禁止無效的this,只能用在構造器,類,對象字面量 // "no-redeclare": 2, //禁止重複聲明變量 // "no-spaced-func": 2, //函數調用時 函數名與()之間不能有空格 // "no-this-before-super": 0, //在調用super()以前不能使用this或super // "no-undef": 2, //不能有未定義的變量 // "no-use-before-define": 2, //未定義前不能使用 // // "camelcase": 0, //強制駝峯法命名 // "no-mixed-spaces-and-tabs": 0, //禁止混用tab和空格 // "prefer-arrow-callback": 0, //比較喜歡箭頭回調 // "arrow-spacing": 0, //=>的前/後括號 // // // 禁止在 componentDidMount 裏面使用 setState // // 禁止在 componentDidUpdate 裏面使用 setState // 'react/no-did-update-set-state': 2, // // 禁止拼寫錯誤 // 'react/no-typos': 2, // // 禁止使用字符串 ref // 'react/no-string-refs': 2, // // @fixable 禁止出現 HTML 中的屬性,如 class // 'react/no-unknown-property': 2, // // 禁止出現未使用的 propTypes // // @off 不強制要求寫 propTypes // 'react/no-unused-prop-types': 2, // // 出現 jsx 的地方必須 import React // // @off 已經在 no-undef 中限制了 // 'react/react-in-jsx-scope': 0, // // 非 required 的 prop 必須有 defaultProps // // @off 不強制要求寫 propTypes // 'react/require-default-props': 0, // // render 方法中必須有返回值 // 'react/require-render-return': 2, // // @fixable 組件內沒有 children 時,必須使用自閉和寫法 // // @off 不必限制 // 'react/self-closing-comp': 0, // // style 屬性的取值必須是 object // 'react/style-prop-object': 2, // // HTML 中的自閉和標籤禁止有 children // 'react/void-dom-elements-no-children': 2, // // 數組中的 jsx 必須有 key // 'react/jsx-key': 2, // // 禁止在 jsx 中使用像註釋的字符串 // 'react/jsx-no-comment-textnodes': 2, // // 禁止出現重複的 props // 'react/jsx-no-duplicate-props': 2, // // 禁止使用未定義的 jsx elemet // 'react/jsx-no-undef': 2, // // jsx 文件必須 import React // 'react/jsx-uses-react': 2, // // 定義了的 jsx element 必須使用 // 'react/jsx-uses-vars': 2, // // @fixable 多行的 jsx 必須有括號包起來 // // @off 不必限制 // 'react/jsx-wrap-multilines': 2, // "react/no-array-index-key": 2, // 遍歷出來的節點必須加key // "react/no-children-prop": 2, // 禁止使用children做爲prop // "react/no-direct-mutation-state": 2, // 禁止直接this.state = 方式修改state 必須使用setState }, };
webpack.common.js
... module: { rules: [ ... { test: /\.(js|jsx)$/, loader: 'eslint-loader', enforce: 'pre', include: [path.resolve(__dirname, 'src')], // 指定檢查的目錄 options: { // 這裏的配置項參數將會被傳遞到 eslint 的 CLIEngine formatter: require('eslint-friendly-formatter'), // 指定錯誤報告的格式規範 }, }, ] } ...
根目錄下新建 .eslintignore 文件 用來制定忽略某些文件的 eslint 校驗
webpack
下載依賴
npm insatll --save-dev stylelint stylelint-config-recommended stylelint-config-standard stylelint-order stylelint-webpack-plugin
stylelint 配置
webpack.dev.js
const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); // 用來縮小(壓縮優化)js文件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map',
plugins: [
new UglifyJSPlugin({ sourceMap: true, }), new CleanWebpackPlugin(),
],
});
package.json
...
"pre-commit": [
"dev", "build"
],
...
根目錄下新建 .stylelintrc.js 文件
module.exports = {
extends: ['stylelint-config-standard', 'stylelint-config-recommended'], plugins: ['stylelint-order'], rules: { 'order/order': [ // "at-rules", // "declarations", 'custom-properties', 'dollar-variables', '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', ], indentation: 'tab', 'color-no-invalid-hex': true, 'font-family-no-missing-generic-family-keyword': null, 'font-family-name-quotes': null, 'function-url-quotes': 'always', 'at-rule-no-unknown': null, 'no-eol-whitespace': null, 'selector-attribute-quotes': 'always', 'string-quotes': 'single', 'selector-pseudo-element-colon-notation': null, 'at-rule-no-vendor-prefix': true, 'media-feature-name-no-vendor-prefix': null, 'media-feature-name-no-unknown': null, 'property-no-vendor-prefix': null, 'selector-no-vendor-prefix': true, 'value-no-vendor-prefix': true, 'selector-pseudo-class-no-unknown': null, 'shorthand-property-no-redundant-values': null, 'at-rule-empty-line-before': null, 'at-rule-name-space-after': null, 'comment-empty-line-before': null, 'declaration-bang-space-before': null, 'declaration-empty-line-before': null, 'function-comma-newline-after': null, 'function-name-case': null, 'function-parentheses-newline-inside': null, 'function-max-empty-lines': null, 'function-whitespace-after': null, 'number-leading-zero': null, 'number-no-trailing-zeros': null, 'rule-empty-line-before': null, 'selector-combinator-space-after': null, 'selector-list-comma-newline-after': null, // "selector-pseudo-element-colon-notation": null, 'unit-no-unknown': null, 'no-descending-specificity': null, 'value-list-max-empty-lines': null, },
};