1、文件初始化
1、安装依赖
npm install webpack webpack-cli -D
2、生成package.json文件
npm init -y{ "name": "react-demo", "version": "1.0.0", "description": "webpack脚手架exercise", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [ "webpack" ], "author": "suanjiaxing <13722807589@163.com>", "license": "ISC" }
3、package.json 脚本配置
"scripts": {
"build": "webpack --mode production"
},
5、根目录新建 src 目录,用于存放源文件,新建/src/index.js,内容任意
console.log("试运行打包")
6、试运行打包
npm run build 后会生成一个 dist 目录,里面是打包后的文件
2、config文件配置
1、根目录新建 config 文件夹
|- config (打包配置目录)
|- PATH.js -- 存储环境变量
|- webpack.common.js -- webpack打包基础配置文件
|- webpack.dev.js -- webpack 开发环境打包配置文件
|- webpack.prod.js -- webpack 生产环境 build打包配置文件
2、PATH.js
/*
* @Descripttion: 存储环境变量
* @version: webpack - excrise
* @Author: 孙佳星
* @LastEditors: 孙佳星
* @Date: 2020-08-13 16:04:54
* @LastEditTime: 2020-08-13 16:24:36
*/
const path = require('path');
module.exports = {
dist: path.resolve(__dirname, '../dist'),
src: path.resolve(__dirname, '../src'),
public: path.resolve(__dirname, '../public'),
};
2、webpack.common.js
/*
* @Descripttion: 公共 config 抽离
* @version: webpack - excrise
* @Author: 孙佳星
* @LastEditors: 孙佳星
* @Date: 2020-08-13 15:50:33
* @LastEditTime: 2020-08-20 19:35:54
*/
const path = require('path');
const PATHS = require("./PATHS")
const webpack = require('webpack');
module.exports = {
/* 入口文件 */
entry: './src/index.js',
/* 出口文件 */
output: {
path: path.resolve(__dirname,PATHS["dist"]),
filename: '[name].[hash:6].js',
},
module: {
rules: []
},
plugins: []
}
3、web pack.dev.js
/*
* @Descripttion: 开发环境
* @version: webpack - excrise
* @Author: 孙佳星
* @LastEditors: 孙佳星
* @Date: 2020-08-13 15:50:10
* @LastEditTime: 2020-08-20 19:36:20
*/
const path = require('path');
const PATHS = require("./PATHS")
const webpack = require('webpack');
module.exports = {
/* 模式 */
mode: 'development',
/* sorce-map */
devtool : 'cheap-module-eval-source-map',
/* 插件 */
plugins: []
}
4、web pack.pro.js
/*
* @Descripttion: 生产环境
* @version: webpack - excrise
* @Author: 孙佳星
* @LastEditors: 孙佳星
* @Date: 2020-08-13 15:50:10
* @LastEditTime: 2020-08-20 19:36:12
*/
const path = require('path');
const PATHS = require("./PATHS")
const webpack = require('webpack');
module.exports = {
/* 生产模式 */
mode: 'production',
/* models */
module: {},
/* 插件 */
plugins: []
}
5、package.json 脚本配置
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack --mode development --config config/webpack.dev.js",
"build": "webpack --mode production --config config/webpack.pro.js"
},
3、HTML 模板
1、安装依赖
npm install html-webpack-plugin -D
2、HTML 模板
|- public -- 静态文件 |- index.html -- 模板文件 |- src |- index.js -- 入口文件<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title><%= htmlWebpackPlugin.options.title %></title> </head> <body> <div id="root"></div> </body> </html>
3、webpack.common.js
const path = require('path');
const PATHS = require("./PATHS")
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
/* 入口文件 */
entry: './src/index.js',
/* 出口文件 */
output: {
path: path.resolve(__dirname,PATHS["dist"]),
filename: '[name].[hash:6].js',
},
/* 规则*/
module: {
rules: []
},
/* 依赖 */
plugins: [
new HtmlWebpackPlugin({
title: 'webpack - excrise',
template: path.resolve( PATHS["public"], 'index.html'),
filename: path.resolve( PATHS["dist"], 'index.html'),
hash: true,
minify: {
removeAttributeQuotes: true, // 去除多余引号
collapseWhitespace:true, // 移除空格
removeComments:true // 移除注释
}
}),
]
}
4、config 合并
1、安装依赖
npm install --save-dev webpack-merge
2、webpack.dev.js
const {merge} = require('webpack-merge'); // 导入 merge 方法
const commonConfig = require('./webpack.common') // 导入公共config
const devConfig = {
mode: 'development',
plugins: []
}
module.exports = merge(commonConfig, devConfig)
3、webpack.pro.js
const {merge} = require('webpack-merge');
const commonConfig = require('./webpack.common')
const proConfig = {
mode: 'production',
module: {},
plugins: []
}
module.exports = merge(commonConfig, proConfig)
4、试运行打包
dist 文件夹下出现 index.html
5、构建本地服务
1、安装依赖
npm install webpack-dev-server --save-dev
2、webpack.dev.js
const path = require('path');
const PATHS = require("./PATHS.js")
const webpack = require('webpack')
const devServer = {
contentBase: path.resolve(PATHS.dist), //本地服务器所加载的页面所在的目录
compress:true, // GZip压缩
historyApiFallback: true, //不跳转
host: '127.0.0.1',
port: 8080,
inline: true, //实时刷新
open: true, //自动打开浏览器
hot:true //开启热更新
};
const devConfig = {
/* 模式 */
mode: 'development',
/* 本地服务 */
devServer,
/* sorce-map */
devtool : 'cheap-module-eval-source-map',
/* 插件 */
plugins: [
new webpack.HotModuleReplacementPlugin() // 热更新
]
}
module.exports = merge(commonConfig, devConfig)
3、package.json
"scripts": {
"dev": "webpack-dev-server --mode development --config config/webpack.dev.js",
},
4、npm run dev 试运行
6、babel支持
1、安装依赖
npm install --save-dev babel-loader @babel/core npm install --save-dev @babel/preset-env npm install --save @babel/polyfill
- babel-loader: 转义 js 文件代码的 loader
- @babel/core:babel 核心库
- @babel/preset-env :转为 es5 代码
- @babel/polyfill : 兼容新的 API。 Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API ,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象
2、webpack.common.js
// 入口文件 /* * entry: { * main: ['@babel/polyfill', path.resolve(PATHS.src, 'index.js')] * }, */ entry:"./src/index.js", // 规则 module: { rules: [ { test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader' } // options 在 .babelrc 定义 } ] },
- entry: {main: ['@babel/polyfill', path.resolve(PATHS.src, 'index.js')]}, 这样配置的话,打包以后代码体积会变得很大。
- "useBuiltIns": "usage":按需加载,只会对我们index.js当前要打包的文件中使用过的语法,比如Promise,map做polyfill,其他es6未出现的语法,我们暂时不去做polyfill,减小打包体积
3、根目录建 .babelrc 文件
{
"presets": [["@babel/preset-env", { "useBuiltIns": "usage" }]]
}
4、入口文件修改
const func = () => {
console.log('hello webpack')
}
func()
new Promise(resolve => console.log('promise'))
class User {
constructor() {
console.log('new User')
}
}
5、试运行
npm run dev / npm run build 试运行 & 打包
7、babel/polyfill 优化
1、安装依赖
npm install --save-dev @babel/plugin-transform-runtime npm install --save @babel/runtime npm install --save @babel/runtime-corejs2
babel-polyfill会污染全局作用域, 如引入Array.prototype.includes修改了 Array 的原型babel-polyfill引入新的对象:Promise、WeakMap等- @babel/runtime-corejs2:@babel/runtime-corejs3 打出来的包比 2 大
( 1 ) @babel/runtime的作用
提取辅助函数。ES6 转码时,babel 会需要一些辅助函数,例如 _extend。babel 默认会将这些辅助函数
内联到每一个 js 文件里, babel 提供了 transform-runtime 来将这些辅助函数“搬”到一个单独的模块
babel-runtime 中,这样做能减小项目文件的大小。
提供
polyfill:不会污染全局作用域,但是不支持实例方法如 Array.includes
(2) @transform-runtime 的作用:
babel-runtime 更像是分散的 polyfill 模块,需要在各自的模块里单独引入,借助 transform-runtime 插件
来自动化处理这一切,也就是说你不要在文件开头 import 相关的 polyfill,你只需使用,transform-runtime 会帮你引入
2、.babelrc
{
"presets": ["@babel/preset-env"],
"plugins": [["@babel/plugin-transform-runtime", { "corejs": 2 }]]
}
3、试运行
npm run dev / npm run build 试运行 & 打包
8、装饰器模式
1、安装依赖
npm install --save @babel/plugin-proposal-decorators
2、.babelrc
{
"presets": [["@babel/preset-env", {"corejs": "2", "useBuiltIns": "usage" }]],
"plugins": [
["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": true }],
["@babel/plugin-transform-runtime", { "corejs": 2 }]
]
}
3、入口文件修改
const func = () => {
console.log('hello webpack')
}
func()
new Promise(resolve => console.log('promise'))
function annotation(target) {
target.annotated = true
}
@annotation
class User {
constructor() {
console.log('new User')
}
}
const p1 = new User()
9、删除上次打包好的文件
1、安装依赖
npm install clean-webpack-plugin -D
2、webpack.pro.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
plugins: [
new CleanWebpackPlugin(),
],
}
10、配置 React
1、安装依赖
npm install --save react react-dom npm install --save-dev @babel/preset-react
- babel-preset-react: jsx 转换成js
2、.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"corejs": "2",
"useBuiltIns": "usage"
},
"react"
],
"@babel/preset-react"
],
"plugins": [
["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": true }],
["@babel/plugin-transform-runtime", { "corejs": 2 }]
]
}
3、新建App.js
|- src |- index.js -- 入口文件 |- App.jsimport React from 'react'; const App = () => <div>佳星加油!!!</div> export default App;
4、修改入口文件
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; ReactDOM.render( <App/>, document.getElementById('root') );
11、React 热替换
1、安装依赖
npm i -D react-hot-loader
- webpack-dev-server的热加载是开发人员修改了代码,代码经过打包,重新刷新了整个页面;
- 热react-hot-loader不会刷新整个页面,它只会替换修改了的代码,做到页面的局部刷新。
- react-hot-loader需要依赖webpack的hotModuleReplacementPlugin热加载插件。
2、babelrc
{
"presets": [
[
"@babel/preset-env",
{
"corejs": "2",
"useBuiltIns": "usage"
},
"react"
],
"@babel/preset-react"
],
"plugins": [
["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": true }],
["@babel/plugin-transform-runtime", { "corejs": 2 }],
"react-hot-loader/babel" // React 模块热替换
]
}
3、App.js
import React from 'react';
import { hot } from 'react-hot-loader/root';
const App = () => <div>佳星加油!!!</div>
export default hot(App);
12、eslint 检查
1、安装依赖
npm install --save-dev eslint eslint-loader npm install --save-dev babel-eslint eslint-plugin-react npm install --save-dev eslint-plugin-import npm install pre-commit --save-dev
- eslint-plugin-import: 校验es6的import规则
- pre-commit :提交前检查是否有格式错误
2、webpack.common.js
{
test: /\.m?js$/,
exclude: /node_modules/,
enforce:true, // 优先执行
loader:'eslint-loader',
options:{
fix: true // 自动修复
}
},
3、package.json
"scripts": { // npm run lint 格式化文件
"lint": "eslint --ext .js --ext .jsx src"
}
"pre-commit": [ // git 提交代码前进行格式检查
"lint"
]
k
4、新增.eslint.js 文件
{
"env": {
"browser": true,
"commonjs": true,
"es6": true
},
"parser": "babel-eslint",
"extends": [
"eslint:recommended",
"plugin:react/recommended"
],
"parserOptions": {
"ecmaVersion": 7,
// 开启实验属性
"ecmaFeatures": {
"experimentalObjectRestSpread": true,
// 修饰器
"experimentalDecorators": true,
"jsx": true
},
"sourceType": "module"
},
"plugins": [
"react"
],
"globals": {
"__DEV__": false,
"__dirname": false,
"window": true,
"define": true,
"history": true,
"location": true,
"wxjs": true,
"$": true,
"WeixinJSBridge": true,
"wx": true,
"process": true,
"qq": true
},
"settings": {
"react": {
"version": "16.2.0"
}
},
"rules": {
// 禁止空函数
"no-empty-function": ["error"],
// 禁止 function 定义中出现重名参数
"no-dupe-args": 2,
// 禁止对象字面量中出现重复的 key
"no-dupe-keys": 2,
// 禁止重复的 case 标签
"no-duplicate-case": 2,
// 禁止出现空代码块,允许 catch 为空代码块
"no-empty": ["error",{"allowEmptyCatch": true}],
// 禁止对 catch 子句的参数重新赋值
"no-ex-assign": 2,
// 禁止不必要的布尔转换
"no-extra-boolean-cast": 2,
// 禁止不必要的括号 //(a * b) + c;//报错
"no-extra-parens": 0,
// 禁止在 if 代码块内出现函数声明
"no-inner-declarations": ["error","both"],
// 禁止在普通字符串中出现模版字符串里的变量形式,如 "Hello ${name}!"
"no-template-curly-in-string": "error",
// 禁止在 return, throw, break 或 continue 之后还有代码
"no-unreachable": "error",
// 不允许标签与变量同名
"no-label-var": 2,
// 禁止 var 声明 与外层作用域的变量同名
"no-shadow": 0,
// 禁止覆盖受限制的标识符
"no-shadow-restricted-names": 2,
// 禁止将变量初始化为 undefined
"no-undef-init": 2,
// 禁止将 undefined 作为标识符
"no-undefined": 0,
// 不允许在变量定义之前使用它们
"no-use-before-define": 0,
/***************
// 风格指南 //
***************/
// 一致缩进4个空格,switch 语句中的 case 子句缩进级别为1,即两个空格
"indent": ["error", 4, {"SwitchCase": 1}],
// 单行最大长度
"max-len": ["error", {"code": 140, "comments": 80}],
// 多行注释风格
"multiline-comment-style": ["error", "starred-block"],
// 强制在对象字面量的属性中键和值之间使用一致的间距
"key-spacing": [2, {"beforeColon": false, "afterColon": true}],
// 要求在注释周围有空行 ( 要求在块级注释之前有一空行)
"lines-around-comment": [2, {"beforeBlockComment": true}],
// 指定数组的元素之间要以空格隔开
"array-bracket-spacing": [2, "never"],
// 禁止或强制在单行代码块中使用空格(禁用)
"block-spacing": [1, "never"],
//强制使用一致的缩进 第二个参数为 "tab" 时,会使用tab,
"brace-style": [2, "1tbs", {"allowSingleLine": true}],
// 控制逗号前后的空格
"comma-spacing": [2, {"before": false,"after": true}],
// 控制逗号在行尾出现还是在行首出现 (默认行尾)
"comma-style": [2, "last"],
// 文件末尾强制换行
"eol-last": 2,
// 要求或禁止在函数标识符和其调用之间有空格
"func-call-spacing": 2,
// 构造函数首字母大写
"new-cap": ["error"],
// 强制所有控制语句使用一致的括号风格
"curly": [2, "all"],
// 禁止 catch 子句的参数与外层作用域中的变量同名
"no-catch-shadow": 0,
// 禁用特定的全局变量
"no-restricted-globals": 2,
// 强制在关键字前后使用一致的空格 (前后腰需要)
"keyword-spacing": 2,
// 禁止使用 Array 构造函数
"no-array-constructor": 2,
// 要求 return 语句之前有一空行
"newline-before-return": 0,
// 要求方法链中每个调用都有一个换行符
"newline-per-chained-call": 1,
// 禁用 continue 语句
"no-continue": 0,
// 禁用 console-log
"no-console":0,
//禁止空格和 tab 的混合缩进
"no-mixed-spaces-and-tabs": [ "error", "smart-tabs"],
// 不允许多个空行
"no-multiple-empty-lines": [2, {"max": 2}],
// 不允许使用嵌套的三元表达式
"no-nested-ternary": 0,
// 强制使用一致的反勾号、双引号或单引号
"quotes": [2, "single", "avoid-escape"],
// 强制分号之前和之后使用一致的空格
"semi-spacing": 2,
/***************
// es6 //
***************/
// 强制 generator 函数中 * 号周围使用一致的空格
"generator-star-spacing": [2, {"before": true,"after": true}],
// 要求generator 函数内有 yield
"require-yield": 2,
// 禁止修改类声明的变量
"no-class-assign": 2,
// 禁止类成员中出现重复的名称
"no-dupe-class-members": 2,
// 要求或禁止模板字符串中的嵌入表达式周围空格的使用
"template-curly-spacing": 1,
// 每个模块只能使用一个import
"no-duplicate-imports": 2,
// 禁止在构造函数中,在调用 super() 之前使用 this 或 super
"no-this-before-super": 2,
// 要求使用 let 或 const 而不是 var
"no-var": 1,
// 要求使用箭头函数作为回调
"prefer-arrow-callback": 0,
// 要求使用 const 声明那些声明后不再被修改的变量
"prefer-const": 0,
// 要求使用模板字面量而非字符串连接
"prefer-template": 0,
/***************
// jsx //
***************/
// 禁止使用已废弃的 api
"react/no-deprecated": "error",
// 禁止未使用的变量
"no-unused-vars": 0,
//在JSX属性中强制或禁止等号周围的空格
"react/jsx-equals-spacing": 2,
"react/jsx-filename-extension": [2, {
"extensions": [".js", ".jsx"]
}],
// 禁止直接修改 this.state
"react/no-direct-mutation-state": "error",
// 禁止出现 HTML 中的属性,如 class
"react/no-unknown-property": "error",
// render 方法中必须有返回值
"react/require-render-return": "error",
// 自闭和标签的反尖括号必须与尖括号的那一行对齐
"react/jsx-closing-bracket-location": ["error",{"nonEmpty": false, "selfClosing": "line-aligned"}],
// jsx 的 children 缩进必须为四个空格
"react/jsx-indent": [ "error",4],
// jsx 的 props 缩进必须为四个空格
"react/jsx-indent-props": ["error",4],
// 禁止出现重复的 props
"react/jsx-no-duplicate-props": "error",
// 禁止出现多余的分号
"no-extra-semi": "error",
// 禁止在数组中出现连续的逗号,如 let foo = [,,]
"no-sparse-arrays": "error",
// 禁止在条件语句中出现赋值操作符,除非这个赋值语句被括号包起来了
"no-cond-assign": ["error","except-parens"],
// 强制在 JSX 属性中一致地使用双引号或单引号
"jsx-quotes": 0,
//链式调用的时候,点号必须放在第二行开头处,禁止放在第一行结尾处
"dot-location": ["error","property"],
// 必须使用 === 或 !==,禁止使用 == 或 !=,与 null 比较时除外
"eqeqeq": ["error", "always",{"null": "ignore"}],
// @fixable 禁止出现没必要的 bind
"no-extra-bind": "error",
// @fixable 禁止出现没必要的 label
"no-extra-label": "error",
// switch 的 case 内必须有 break, return 或 throw
"no-fallthrough": "error",
// 禁止重复定义变量
"no-redeclare": "error",
// 禁止在 return 语句里赋值
"no-return-assign": 0
}
}
5、VScode配置
"editor.tabSize": 4, "editor.fontSize": 14, // eslint 配置 "editor.codeActionsOnSave": { "source.fixAll": true, "source.fixAll.eslint": true }, "javascript.format.insertSpaceBeforeFunctionParenthesis": true, //让函数(名)和后面的括号之间加个空格 "vetur.format.defaultFormatter.html": "js-beautify-html", //格式化.vue中html "explorer.confirmDragAndDrop": false, "explorer.confirmDelete": false,下载 ESlint 插件,进行如下配置
13、CSS & Less
1、安装依赖
npm install css-loader style-loader -D npm install less less-loader --save-dev npm install --save-dev mini-css-extract-plugin
css-loader: 处理 css 文件style-loader: import 导入的样式文件,打包到 js 文件中,运行 js 文件时,将样式自动插入到标签- mini-css-extract-plugin:import 导入的样式文件,打包成一个实际的 css 文件,结合 html-webpack-plugin,在 dist/index.html 中以 link 形式插入;默认将 js 中 import 的多个 css 文件,打包时合成一个
2、webpack.common.config
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader','css-loader']
},
]
}
2、webpack-dev.config
module: {
rules: [
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader'],
exclude: /node_modules/
}
]
},
3、webpack.dev.js
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module: {
rules: [
{
test: /\.(scss|less)$/,
use: [
{
loader: MiniCssExtractPlugin.loader // CSS 单独抽离一个文件
},
'css-loader',
'less-loader'
],
exclude: /node_modules/
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[hash:6].css'
})
]
3、试运行
|- src |- index.js -- 入口文件 |- App.js |- page |- Home |- index.js |- style.lesshome/index
import React from 'react' import "./style.less" export default function index() { return ( <div> 你看,你多坚强啊! 你在自己的世界里,活成了一个英雄! 玻璃晴朗,橘子辉煌! </div> ) }home/style.less
@color:red; div{ color:@color }App
import React from 'react'; import { hot } from 'react-hot-loader/root'; import Home from './page/Home' const App = () => <div> 佳星加油!!! <Home/> </div> export default hot(App);
- npm run dev 样式生效
- npm run build 单独生成 style 文件,单机 html 文件,样式生效
14、CSS代码压缩
1、安装依赖
npm install --save-dev optimize-css-assets-webpack-plugin npm install -D uglifyjs-webpack-plugin
- optimize-css-assets-webpack-plugin:压缩 CSS 代码
- uglifyjs-webpack-plugin:optimization.minimizer会覆盖webpack默认提供的规则,,比如不会再压缩 JS 代码,需要该插件
2、webpack.pro.js
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const prodConfig = {
mode: 'production',
devtool: 'cheap-module-source-map',
optimization: {
minimizer: [
new UglifyJsPlugin({
sourceMap: true,
parallel: true, // 启用多线程并行运行提高编译速度
}),
new OptimizeCSSAssetsPlugin({}),
]
}
}
15、属性或选择器前缀
1、安装依赖
npm install postcss-loader autoprefixer -D
- postcss-loader:加前缀
- autoprefixer:配合postcss-loader
2、webpack.dev.config
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: true,
plugins: loader => [
require('autoprefixer') // 添加前缀
]
}
},
'less-loader'
],
exclude: /node_modules/
}
3、webpack.pro.js
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader // CSS 单独抽离一个文件
},
'css-loader',
{
loader: 'postcss-loader', // 属性或选择器添加前缀处理
options: {
ident: 'postcss',
sourceMap: true,
plugins: loader => [ require('autoprefixer') ]
}
},
'less-loader'
],
exclude: /node_modules/
}
4、package.json
"browserslist": {
"development":[
"last 2 chrome version",
"last 2 firefox version",
"last 2 safari version"
],
"production":[
"> 1%",
"last 2 versions",
"not dead",
"not op_mini all",
"not ie <= 10"
]
}
16、图片loader
1、安装依赖
npm install url-loader file-loader --save-dev
- 依赖于
file-loader,把图片转换成base64嵌入html,如果超出一定阈值则交给file-loader- 只需安装url-loader就行,url-loader包含file-laoder
2、webpack.common.js
module: {
rules: [
{
test:/\.(png|jpg|gif|ttf|eot|woff(2)?)(\?[=a-z0-9]+)?$/,
loader: 'url-loader',
options:{
limit:8 * 1024, // 8 kb以下转 base64
esModule:false, // 关闭默认 es模块引入方式
outputPath: 'images', // 将文件打包到哪里
publicPath: './images',
name: '[hash:8].[ext]' // .ext 文件扩展名,jpg\png
}
},
]
}
3、试运行
import React from 'react' import img from '../../static/image/fate--saber.jpg' export default function index() { return ( <div> 你看,你多坚强啊! 你在自己的世界里,活成了一个英雄! 玻璃晴朗,橘子辉煌! <img src={img}/> </div> ) }|- dist |- index.js -- 入口文件 |- main.js |- main.css |- image文件夹juejin.cn/post/685457… React项目中webpack加载svg
17、静态资源加载
1、安装依赖
npm install copy-webpack-plugin --save-dev
2、webpack.common.js
const CopyPlugin = require('copy-webpack-plugin'); plugins: [ new CopyPlugin({ patterns: [ { from: path.resolve(process.cwd(),'src/assets/fonts'), to: path.resolve(process.cwd(),'dist/statics/fonts'), } ] }) ]|- dist |- index.js -- 入口文件 |- main.js |- main.css |- image文件夹 |- statics |- fonts // 字体文件
3、index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><%= htmlWebpackPlugin.options.title %></title>
<link type="text/css" rel="stylesheet" href="./statics/fonts/iconfont.css">
</head>
<body>
<div id="root"></div>
</body>
</html>
1、oneOf
1、webpack.common.js
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
enforce:'pre', // 优先执行
loader:'eslint-loader',
options:{
fix: true // 自动修复
}
},
{
oneOf:[
{
test: /\.css$/,
use: ['style-loader','css-loader']
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: { loader: 'babel-loader' } // options 在 .babelrc 定义
},
{
test:/\.(png|jpg|gif|ttf|eot|woff(2)?)(\?[=a-z0-9]+)?$/,
loader: 'url-loader',
options:{
limit:8 * 1024, // 8 kb以下转 base64
esModule:false, // 关闭默认 es模块引入方式
outputPath: 'images', // 将文件打包到哪里
publicPath: './images',
name: '[hash:8].[ext]' // .ext 文件扩展名,jpg\png
}
}
]
}
]
}
2、soure-map
// 开发环境
eval-cheap-source-map
cheap-module-source-map
eval-source-map
// 生产环境
hidden-source-map
3、tree-shaking
去除无用代码
- 使用 es6 module
- 开启 production
package.json
"sideEffects":["*.css","*.less"]
4、缓存
1、babel缓存
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader' ,
options: {
cacheDirectory: true
}
}
},
2、webpack-pro.js
hash 换成 contenthash
/* 出口文件 */ output: { path: path.resolve(__dirname,PATHS["dist"]), filename: '[name].[contenthash:6].js', }, /* 插件 */ plugins: [ /* 删除上一次打包生成的文件 */ new CleanWebpackPlugin(), /* CSS 单独抽离为一个文件 */ new MiniCssExtractPlugin({ filename: '[name].[contenthash:6].css' }), ],
5、代码分割
1、webpack.pro.js
module.exports = {
entry: './src/index.js',
module: { },
plugins: [],
optimization:{
splitChunks:{
minSize: 0, // 默认30000(30kb),但是demo中的文件都很小,minSize设为0,让每个文件都满足大小条件
cacheGroups: {
vendor: { // nodeModules 代码单独打包成一个 chunk 输出
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: "initial",
name: "vendor",
},
commons: { // 多次import的文件打包成一个单独的common.js
chunks: 'initial',
minChunks: 2,
maxInitialRequests: 5,
name: 'common'
}
}
}
}
}
6、多进程打包
1、安装依赖
npm i thread-loader -D
2、babel - loader 开启多进程
{ test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: [ { loader:'thread-loader', // 开启多进程打包 options:{ workers:2 } }, { loader: 'babel-loader' , options: { cacheDirectory: true } } // options 在 .babelrc 定义 ] },开启多进程 600 ms,js代码非常多时,使用
8、作用域提升
module.exports = {
mode: 'production',
entry: './src/index.js',
output: { ... },
plugins: [
new webpack.optimize.ModuleConcatenationPlugin(),
]
}
1、antD 引入
1、安装依赖
npm install --save-dev babel-plugin-import antd
- babel-plugin-import : 按需引入antd
2、babel.rc
{
"presets": [
[
"@babel/preset-env",
{
"corejs": "2",
"useBuiltIns": "usage"
},
"react"
],
"@babel/preset-react"
],
"plugins": [
["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": true }],
["@babel/plugin-transform-runtime", { "corejs": 2 }],
["import",{
"libraryName": "antd",
"libraryDirectory": "es",
"style":"css"}
], // babel-plugin-import 配置
"react-hot-loader/babel"
]
}
3、webpack.common.js
module: { rules: [ { test: /\.css$/, use: ['style-loader','css-loader'] } ] ]
- antd 样式为 CSS 样式,新增一条 CSS 规则
4、webpack.dev.js
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: true,
plugins: loader => [
require('autoprefixer') // 添加前缀
]
}
},
{
loader: "less-loader",
options: {
javascriptEnabled: true
}
}
],
exclude: /node_modules/
}
5、试运行
import React from 'react' import { Button } from 'antd'; import img from '../../static/image/fate--saber.jpg' export default function index() { return ( <div> <Button type="primary">Primary Button</Button> 你看,你多坚强啊! 你在自己的世界里,活成了一个英雄! 玻璃晴朗,橘子辉煌! <img src={img}/> </div> ) }npm run build
npm run dev 试运行看样式是否生效
2、配置项目别名
Resolve 配置 Webpack 如何寻找模块所对应的文件
webpack.common.js
module.exports = {
/* 入口文件 */
entry: './src/index.js',
...
resolve: {
extensions: ['.js', '.jsx'], // 导入语句没带文件后缀,webpack自动带上后缀文件
alias: {
assets: path.resolve(PATHS.src, 'assets'),
component: path.resolve(PATHS.src, 'component'),
page: path.resolve(PATHS.src, 'page'),
until: path.resolve(PATHS.src, 'until'),
server: path.resolve(PATHS.src, 'server'),
router: path.resolve(PATHS.src, 'router'),
store: path.resolve(PATHS.src, 'store'),
layout: path.resolve(PATHS.src, 'layout'),
tools: path.resolve(PATHS.src, 'tools')
}
}
}
3、自定义主题
1、根文件新建 themes.js
module.exports = {
'primary-color':"#f0f", // 全局主色
'link-color':" #1890ff", // 链接色
'success-color':" #52c41a", // 成功色
'warning-color':" #faad14", // 警告色
'error-color':" #f5222d", // 错误色
'font-size-base':" 14px", // 主字号
'heading-color':"rgba(0, 0, 0, 0.85)", // 标题色
'text-color':" rgba(0, 0, 0, 0.65)", // 主文本色
'text-color-secondary ':" rgba(0, 0, 0, .45)", // 次文本色
'disabled-color ':" rgba(0, 0, 0, .25)", // 失效色
'border-radius-base':" 4px", // 组件/浮层圆角
'border-color-base':" #d9d9d9", // 边框色
'box-shadow-base':" 0 2px 8px rgba(0, 0, 0, 0.15)", // 浮层阴影
}
2、webpack.dev.js
const themes = require('../themes')
...
module: {
rules: [
{
oneOf:[
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: true,
plugins: loader => [ require('autoprefixer') ]
}
},
{
loader: 'less-loader',
options: {
lessOptions: { // 如果less@5,去掉lessOptions,直接options配置
modifyVars: themes,
javascriptEnabled: true,
}
},
}
],
// exclude: /node_modules/ // node_modules/antd 不能过滤
},
]
}
]
},
3、webpack.pro.js
const themes = require('../themes')
module: {
rules: [
{
oneOf:[
{
test: /\.(css|less)$/,
use: [
{
loader: MiniCssExtractPlugin.loader // CSS 单独抽离一个文件
},
'css-loader',
{
loader: 'postcss-loader', // 属性或选择器添加前缀处理
options: {
ident: 'postcss',
sourceMap: true,
plugins: () => [ require('autoprefixer') ]
}
},
{
loader: 'less-loader', // 属性或选择器添加前缀处理
options: {
lessOptions: {
modifyVars: themes,
javascriptEnabled: true,
}
}
}
],
// exclude: /node_modules/
},
]
}
]
},
4、.babelrc / babel-plugin-import更改配置
因为使用babel-plugin-import,需要做一些更改
{ "presets": [ [ "@babel/preset-env", { "corejs": "2", "useBuiltIns": "usage" }, "react" ], "@babel/preset-react" ], "plugins": [ ["@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": true }], ["@babel/plugin-transform-runtime", { "corejs": 2 }], ["import",{ "libraryName": "antd", "libraryDirectory": "lib", "style":true }], // babel-plugin-import 配置 "react-hot-loader/babel" ] }
4、配置全局变量
DefinePlugin 允许创建一个在编译时可以配置的全局常量
1、package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --mode development --config config/webpack.dev.js --env.API=dev",
"server:dev": "webpack-dev-server --open --config config/webpack.dev.js --env.API=server:dev",
"build": "webpack --mode production --config config/webpack.pro.js --env.API=build:dev",
"build:local": "webpack --progress --config config/webpack.prod.js --env.API=build:local",
"lint": "eslint --ext .js --ext .jsx src"
},
2、web pack.comon.js
const path = require('path');
const PATHS = require("./PATHS")
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
// 获取环境变量
let argv = process.argv, // 启动传入的命令行参数
envAPI = 'dev'
for(let i = 0; i < argv.length; i++) {
let arg = argv[i];
if(arg.startsWith('--env.API=')) {
envAPI = arg.replace('--env.API=', '')
}
}
module.exports = {
plugins: [
new HtmlWebpackPlugin({
...
})
new CopyPlugin({
...
}),
new webpack.DefinePlugin({
API_CONFIG: JSON.stringify(envAPI)
}) // 全局变量
]
}
3、Home.js
import React,{ useEffect } from 'react' export default function index () { useEffect( () => { console.log(API_CONFIG) },[]) return ( <div> home </div> ) }npm run dev 本地运行,控制台输出
dev
5、前端代理配置
const devServer = {
stats: 'errors-only',
contentBase: path.resolve(PATHS.dist),
historyApiFallback: true,
host: '127.0.0.1',
port: 80,
hot: true,
inline: true,
disableHostCheck: true,
open: 'Google Chrome',
progress: true,
proxy: {
'/api/*': {
target: 'http://skynet-eye.dev.vivo.xyz:8080', //要跳转的域名
pathRewrite: {
'/api': '',
},
changeOrigin: true,
secure: false,
},
'/common/*': {
target: 'http://fapi.vmic.xyz/mock/494/', //要跳转的域名
pathRewrite: {
'/common': '',
},
changeOrigin: true,
secure: false,
},
}
}