Webpack5.x + Babel7.x + React17.0.2 + Antd4.x平臺搭建V2.0
Arena
Webpack5.x + Babel7.x + React17.0.2 + Antd4.x平臺搭建V2.0 -> 本文代碼地址
項(xiàng)目初始化
通過npm init
初始化項(xiàng)目,一路yes,生成package.json文件
安裝webpack5
npm i -g webpack webpack-cli
npm i -D webpack webpack-cli
安裝babel7
babel是js兼容性處理工具盐肃,負(fù)責(zé)把es6+代碼轉(zhuǎn)換為es5代碼供瀏覽器識別
- 全局安裝
@babel/cli
@babel/core
搅轿,安裝后可檢查babel版本
npm i -g @babel/cli @babel/core
babel -V //7.14.5 (@babel/core 7.14.6)
- 項(xiàng)目安裝
@babel/core
@babel/preset-env
@babel/preset-react
babel-loader
幕随,同時(shí)安裝@babel/polyfill
npm i -D @babel/core @babel/preset-env @babel/preset-react babel-loader @babel/plugin-proposal-class-properties core-js
各模塊功能簡介:
- @babel/core: 用來轉(zhuǎn)碼的核心模塊茅逮,默認(rèn)只轉(zhuǎn)換新語法言缤,不轉(zhuǎn)換新API(如Iterator膊存、Generator导而、Set、Map膝舅、Proxy嗡载、Reflect、Symbol仍稀、Promise等全局對象洼滚,以及一些定義在全局對象上的方法)
- babel-loader: webpack用babel處理js/jsx文件的loader,用來轉(zhuǎn)換代碼
- @babel/preset-env: 設(shè)置babel-loader做基本兼容性處理技潘,不能處理高級API
- @babel/preset-react: 設(shè)置對react語法的轉(zhuǎn)換
- @babel/plugin-proposal-class-properties: 設(shè)置支持類的屬性聲明
- core-js: 讓高級API生效的庫
安裝webpack各種常用加載器遥巴、插件和工具
npm i -D clean-webpack-plugin html-webpack-plugin
npm i -D file-loader url-loader style-loader css-loader
npm i -D webpack-dev-server webpack-merge
各模塊功能簡介:
- clean-webpack-plugin: 每次build前清理dist目錄
- html-webpack-plugin: 用指定html模板構(gòu)建入口html文件
- file-loader: 處理可支持的資源文件類型(如圖片、字體等資源)享幽,打包到dist目錄中
- url-loader:功能同file-loader铲掐,區(qū)別是增加limit選項(xiàng),小于limit大小的圖片會(huì)被轉(zhuǎn)碼為base64直接插入到j(luò)s文件中
- css-loader: 將css文件變成樣式字符串值桩,以commonjs模塊形式加載到j(luò)s中
- style-loader: 創(chuàng)建style標(biāo)簽摆霉,將css-loader生成的樣式字符串放到標(biāo)簽里,插入到html的head中
- webpack-dev-server: 開發(fā)模式的熱更新,注意3.x版本使用方法跟2.x不同
- webpack-merge: 合并webpack配置文件的工具
查看本地webpack各模塊版本
npx webpack --version
// webpack 5.42.0
// webpack-cli 4.7.2
// webpack-dev-server 3.11.2
安裝React17.0.2依賴
npm i -S react react-dom react-router-dom
安裝eslint
-
本地安裝eslint
npm i -D eslint
-
初始化并生成配置文件
.eslintrc.js
,各初始化參數(shù)可以先隨便選携栋,后面再做修改./node_modules/.bin/eslint --init
-
安裝對babel和react的支持
npm i -D babel-eslint eslint-plugin-react eslint-plugin-react-hooks
-
引入Airbnb規(guī)則
npm i -D eslint-config-airbnb eslint-plugin-import eslint-plugin-jsx-a11y
-
修改.eslintrc.js配置文件
module.exports = { "env": { "browser": true, "es2020": true, "node": true }, "extends": [ "airbnb", ], "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly", "Babel": true, "React": true }, "parser": "babel-eslint", "parserOptions": { "ecmaFeatures": { "jsx": true }, "ecmaVersion": 11, "sourceType": "module" }, "plugins": [ "react" ], "rules": { "linebreak-style": [ "off", "unix" ], "quotes": [ "error", "single" ], "semi": [ "error", "always" ], // 禁止縮進(jìn)錯(cuò)誤 "indent": 0, // 關(guān)閉不允許使用 no-tabs "no-tabs": "off", "no-console": 1, // 設(shè)置不沖突 underscore 庫 "no-underscore-dangle": 0, // 箭頭函數(shù)直接返回的時(shí)候不需要 大括號 {} "arrow-body-style": [2, "as-needed"], "no-alert": "error", // 最大長度關(guān)閉 "max-len": 0, // 設(shè)置是否可以重新改變參數(shù)的值 "no-param-reassign": 0, // 允許使用 for in "no-restricted-syntax": 0, "guard-for-in": 0, // 不需要每次都有返回 "consistent-return": 0, // 允許使用 arguments "prefer-rest-params": 0, // 允許返回 await "no-return-await": 0, // 不必在使用前定義 函數(shù) "no-use-before-define": 0, // 允許代碼后面空白 "no-trailing-spaces": 0, // 關(guān)閉大括號內(nèi)的換行符要求 "object-curly-newline": 0, // 有一些 event 的時(shí)候搭盾,不需要 role 屬性,不需要其他解釋 "jsx-a11y/no-static-element-interactions": 0, "jsx-a11y/click-events-have-key-events": 0, // 類成員之間空行問題 "lines-between-class-members": 0, // 不區(qū)分是否在 despendencies "import/no-extraneous-dependencies": 0, // 引用時(shí)候根據(jù)根目錄基礎(chǔ) "import/no-unresolved": 0, // 關(guān)閉解構(gòu)賦值報(bào)錯(cuò) "react/destructuring-assignment": 0, // 允許在 .js 和 .jsx 文件中使用 jsx "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], // 不區(qū)分是否是 無狀態(tài)組件 "react/prefer-stateless-function": 0, // prop-types忽略一些屬性 "react/prop-types": [1, { ignore: ["children", "history", "form"], }], // 關(guān)閉禁止prop-types類型 "react/forbid-prop-types": 0, // 關(guān)閉default-props檢查 "react/require-default-props": 0, // 關(guān)閉禁止屬性使用...運(yùn)算符 "react/jsx-props-no-spreading": 0, // 關(guān)閉括號合攏標(biāo)記換行報(bào)錯(cuò) "react/jsx-closing-bracket-location": 0, // 關(guān)閉state初始方式限制 "react/state-in-constructor": 0, // 關(guān)閉react一行表達(dá)式數(shù)量限制 "react/jsx-one-expression-per-line": 0, } };
新建webpack配置文件
-
在根目錄下新建config目錄婉支,新建如下三個(gè)配置文件:
- webpack.base.conf.js為公用配置
- webpack.dev.conf.js為開發(fā)環(huán)境配置鸯隅,繼承自webpack.base.conf.js
- webpack.prod.conf.js為生產(chǎn)環(huán)境配置,繼承自webpack.base.conf.js
-
修改webpack.base.conf.js文件
'use strict' const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = { // 入口起點(diǎn) entry: { app: './src/index.js', }, // 輸出 output: { path: path.resolve(__dirname, '../dist'), filename: '[name].js', }, // import引入這些類型文件時(shí)這些擴(kuò)展名可以省略 resolve: { extensions: ['.ts', '.tsx', '.js', '.json', '.jsx'], }, // loader module: { rules: [ { test: /\.js|jsx$/, exclude: /node_modules/, // 屏蔽不需要處理的文件(文件夾) loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', // 處理ES6新語法兼容 { useBuiltIns: 'usage', corejs: 3, // core-js處理ES6新API兼容 }, ], '@babel/preset-react', // 處理React兼容性 ], plugins: [ ['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }], // 處理antd樣式 '@babel/plugin-proposal-class-properties', // 處理類屬性定義 ], }, }, { test: /\.css$/, use: [ // 'style-loader', MiniCssExtractPlugin.loader, 'css-loader', ], }, ], }, // 插件 plugins: [ new HtmlWebpackPlugin({ filename: 'index.html', template: './src/index.html', // favicon: './static/favicon.ico', inject: 'body', }), new MiniCssExtractPlugin({ filename: 'css/built.css', }), ], };
-
修改webpack.dev.conf.js文件
//webpack.dev.conf.js const { merge } = require('webpack-merge'); const webpack = require('webpack'); const baseWebpackConfig = require('./webpack.base.conf'); module.exports = merge(baseWebpackConfig, { // 模式 mode: 'development', // 調(diào)試工具 devtool: 'inline-source-map', // 開發(fā)服務(wù)器 devServer: { contentBase: false, // 默認(rèn)webpack-dev-server會(huì)為根文件夾提供本地服務(wù)器向挖,如果想為另外一個(gè)目錄下的文件提供本地服務(wù)器蝌以,應(yīng)該在這里設(shè)置其所在目錄 historyApiFallback: true, // 在開發(fā)單頁應(yīng)用時(shí)非常有用,它依賴于HTML5 history API何之,如果設(shè)置為true跟畅,所有的跳轉(zhuǎn)將指向index.html compress: true, // 啟用gzip壓縮 inline: true, // 設(shè)置為true,當(dāng)源文件改變時(shí)會(huì)自動(dòng)刷新頁面 hot: true, // 模塊熱更新帝美,取決于HotModuleReplacementPlugin host: '127.0.0.1', // 設(shè)置默認(rèn)監(jiān)聽域名碍彭,如果省略,默認(rèn)為“l(fā)ocalhost” port: 8703, // 設(shè)置默認(rèn)監(jiān)聽端口悼潭,如果省略庇忌,默認(rèn)為“8080”, open: true, // 默認(rèn)打開瀏覽器進(jìn)入頁面 }, // 插件 plugins: [ new webpack.HotModuleReplacementPlugin(), ], optimization: { nodeEnv: 'development', moduleIds: 'named', }, target: 'web', });
-
修改webpack.prod.conf.js文件
//webpack.prod.conf.js 'use strict' const { merge } = require('webpack-merge'); const path = require('path'); const webpack = require('webpack'); // 注意:此插件3.0版本引用時(shí)候需要大括號,2.0版本則不用 const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); const baseWebpackConfig = require('./webpack.base.conf'); module.exports = merge(baseWebpackConfig, { // 模式 mode: 'production', // 調(diào)試工具 devtool: 'source-map', // 輸出 output: { path: path.resolve(__dirname, '../dist'), filename: 'js/[name].[chunkhash].js', }, // 插件 plugins: [ new CleanWebpackPlugin(), new webpack.ids.HashedModuleIdsPlugin(), new BundleAnalyzerPlugin(), ], // 代碼分離相關(guān) optimization: { nodeEnv: 'production', runtimeChunk: { name: 'manifest', }, splitChunks: { minSize: 30000, minChunks: 1, maxAsyncRequests: 5, maxInitialRequests: 3, name: false, cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendor', chunks: 'initial', }, }, }, }, });
-
修改package.json的scripts部分, 注意devServer的啟動(dòng)命令跟老版本的區(qū)別
"scripts": { "dev": "npx webpack serve --progress --config config/webpack.dev.conf.js", "start": "npm run dev", "build": "npx webpack --progress --config config/webpack.prod.conf.js" },
安裝Ant Design
-
安裝antd和babel-plugin-import工具實(shí)現(xiàn)按需加載
npm i -S antd babel-plugin-import
-
修改webpack.base.conf.js配置文件js的loader部分
{ test: /\.js|jsx$/, exclude: /node_modules/,// 屏蔽不需要處理的文件(文件夾)(可選) loader: 'babel-loader', options:{ presets: [ [ '@babel/preset-env', // 處理ES6新語法兼容 { useBuiltIns: 'usage', corejs: 3, // core-js處理ES6新API兼容 }, ], '@babel/preset-react' // 處理React兼容性 ], plugins: [ "@babel/plugin-proposal-class-properties", // 處理類屬性定義 ['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }], // 處理antd樣式 ] } },
安裝styled-components
-
安裝styled-components
npm i -S styled-components
demo代碼
-
在src目錄下新建index.html和index.js文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 防止頁面緩存 --> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <meta http-equiv="Expires" content="0"> <title>Document</title> </head> <body> <div id="app"></div> </body> </html>
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Button } from 'antd';
import styled from 'styled-components';
const Sdiv = styled.div`
background-color: pink;
`;
const App = () => (
<Sdiv>
Hello React
<Button type="primary">Antd Button</Button>
</Sdiv>
)
ReactDOM.render(<App />, document.getElementById('app'));
-
運(yùn)行
npm start //啟動(dòng)devServer npm run build //打包
css文件單獨(dú)打包
-
如果不想把css文件跟js文件打到一起舰褪,可以利用mini-css-extract-plugin插件將css文件獨(dú)立出來
npm i -D mini-css-extract-plugin
-
修改webpack.base.conf.js文件中css處理模塊的代碼
// 開頭引入插件 const MiniCssExtractPlugin = require('mini-css-extract-plugin'); …… // module - rules - css-loader部分修改:用MiniCssExtractPlugin.loader替換style-loader { test: /\.css$/, use: [ // 'style-loader', MiniCssExtractPlugin.loader, 'css-loader' ], } …… // plugins增加一個(gè)插件 new MiniCssExtractPlugin({ filename: 'css/built.css' //打包位置 })
查看打包文件大小和構(gòu)成的可視化工具
-
安裝BundleAnalyzerPlugin
npm i -D webpack-bundle-analyzer
-
在webpack.prod.conf.js文件中修改配置
// 開頭引入插件 const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); …… // plugins中添加插件 new BundleAnalyzerPlugin(),