-
webpack有哪些能力?
提到webpack,提到webpack能干什么?
初学者都能下意识地都能回答出:webpack是一个打包工具。
这么说没什么不对,但是失于片面。webpack的目的是为了构建出一个高质量的web应用,于此同时,需要提供一整套的本地开发流程,可以让开发者更愉快地开发出所需的功能。
- 前者对应的是webpack的打包能力,因为浏览器只认识js, css, html,webpack把开发中用到的各种文件都集成起来,使其能在页面中被浏览。
- 后者对应的是开发者体验,诸如本地服务预览,热更新,wtach模式,sourceMap等等,让开发者获得更好地开发体验。
-
打包工具
前端开发工作可以粗略地分为两类,一类是应用开发,一类是包的开发,二者都会用到打包,不过webpack更多用于网页应用的开发(npm包开发打包用rollup较好)。
为什么开发时为什么需要打包?
-
将代码模块化,可以避免作用域污染等问题,降低开发者的心智负担,更符合分治的开发原则。开发时可以直接使用import这种模块化语句,直接简单。
-
将多个文件合成为一个文件可以降低网络请求的次数,加快网页加载速度。
-
使用多种类型的文件,然后打包到一起,用浏览器能识别的形式展示(主要是js)。
打包的产物是什么?
webpack开发应用时产物是iife(立即执行函数)形式的,简单情况下,会打包出一个
bundle.js这样的文件,然后在一个html文件中进行引用。当然webpack也可以打包es,cjs等格式的产物,不过是在打包npm包的时候。-
开发工具
webpack的目的和产物是得到可以部署的打包后代码,通常这些代码主体部分就是纯js文件,但是在开发中我们会使用到很多“方言”,如ts,React 的jsx语法,less 或 scss类型的css语言,这些内容需要用编译工具编译成纯js语言,这些编译工具都可以通过loader工具集成在webpack之中。这是打包工具的内容,同样也是开发工具在webpack中的表现。
除此之外以下列出webpack提供的便捷开发工具能力:
-
本地服务器预览:webpack-dev-server提供本地服务器预览开发内容,同时可以做一些网址的代理。
-
sourceMap:开发出的内容一般都经过压缩,代码变得不易阅读,开发时需将实际源码与运行代码通过map文件关联起来,方便定位问题。
-
watch模式:类似于nodemon,当文件发生变化,node重新编译代码,预览页面刷新。实际上devServer也能提供这种服务。
-
热更新(hrm):如果代码每更新一次代码就重编译太慢了,热更新可以不刷新页面,只改变代码变更影响的部分内容,实时显示变更,避免了在开发弹窗等内容时,每刷新一次都得重新点开弹窗的尴尬。
-
优化工具
所谓web的优化狭义上来讲就是打包产物大小的优化,产物越小,页面展示得越快。
-
treeShaking:用es6的模块语法(import, export)可以触发webpack生产环境默认的treeShaking。在应用中引用npm包的最好只引用用到的部分,否则会影响对于npm包的treeShaking。
-
路由懒加载:结合代码分块进行,react等框架也有对应的解决方案。
-
cdn代替引用:用cdn地址直接在html中引入较大的包。
-
代码优化工具:打包时对代码进行压缩。
-
gzip优化:使用Nginx的话需要在服务端做一些配置。
-
学习webpack的目标
-
开发应用 (react + scss + ts )
开发体验:本地服务器 & 热更新 & sourceMap。
代码运行:loader& plugin配置。
-
基础代码运行(js + devServer + css | scss)
首先搭建一个基础的代码架子,基础的配置可以代码实时更新,并简单区分开发模式和生产模式。
代码结构:
webpack-case ├─package-lock.json ├─package.json ├─webpack.config.js ├─src | ├─index.js | └index.scss ├─dist简要列一下主要内容:
-
pakage.json:引入几个需要的npm包,简单区分build和start两种环境,用webpack-dev-server开启实时更新。
-
{ "name": "webpack-case", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo "Error: no test specified" && exit 1", "build": "NODE_ENV=production webpack", "start": "NODE_ENV=development webpack server --open" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^6.7.3", "html-webpack-plugin": "^5.5.0", "sass": "^1.57.1", "sass-loader": "^13.2.0", "style-loader": "^3.3.1", "webpack": "^5.75.0", "webpack-cli": "^5.0.1", "webpack-dev-server": "^4.11.1" } }
-
-
webpack.config.js: 简单配置了文件的出口入口,还有loader和plugin
-
const path = require('path'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), clean: true }, mode: process?.env?.NODE_ENV === 'production' ? 'production': 'development', devServer: { static: './dist', }, module: { rules: [ { test: /.s?css$/i, use: ['style-loader', 'css-loader', 'sass-loader'], }, ], }, plugins: [ new HtmlWebpackPlugin({ title: 'webpack-case', }), ], }
-
./src/index.js
import './index.scss'; const div = document.createElement('div'); div.className = 'text'; div.innerHTML='webpack-case is there'; document.body.appendChild(div);./src/index.scss
$color: #e0c9ba; .text { color: $color; }-
添加react + antd以及基于react的热更新
参考从零配置webpack 5 + React脚手架(一) - 掘金
react引入需要添加相应loader
{ test: /.(js|jsx)$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env', '@babel/preset-react'], plugins: ['@babel/plugin-transform-runtime', '@babel/plugin-proposal-class-properties'], }, }, },添加默认拓展名:
resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'], },配置react热更新:
devServer: { static: './dist', hot: true, } // App.jsx import { hot } from 'react-hot-loader/root'; export default hot(App);-
添加typescript
添加ts-loader
{ test: /.tsx?$/, use: 'ts-loader', exclude: /node_modules/, },添加react库相关typs包
"@types/react": "^18.0.27", "@types/react-dom": "^18.0.10",react等包的引入方式改变:
import * as React from "react"; import * as ReactDOM from 'react-dom';-
打包优化
Cdn 引入react包:
// webpack.config.js externals: { react: 'React', 'react-dom': 'ReactDOM', } // 包名: 代码中使用的对象 // public/index.html <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js" ></script> <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" ></script>treeShaking:
使用es6语法在打包production模式下会自动优化。有些包内部可能不支持treeShaking,需要只引入特定的部分。
懒加载 : 一般结合react路由使用。
-
css隔离
首先引用一张网络上的css隔离方式对比图:
由上可知,css modules是一种较好的通过工具约束来隔离css的方法,其缺点是依赖打包工具,但是我们讨论的就是如何通过打包工具实现css隔离,这一点天然成立。此外BEM和预处理器一般也都会在项目中作为一种css的默认规范被使用到。
引入方式
import styles from './App.scss';使用css方式
<div className={styles.text}>hello webpack test</div>webpack, css-loader配置
{ test: /.s?css$/i, use: [ 'style-loader', { loader: 'css-loader', options: { modules: { auto: resourcePath => resourcePath.endsWith('.scss'), localIdentName: '[local]_[hash:base64:10]', }, importLoaders: 1, }, }, 'sass-loader', ], exclude: /node_modules/, },-
配置lint
-
具体过程参考👋 Hello ESLint | Linter上手完全指南
安装7版本的eslint:npm i -D eslint@7.19.0 最新版本可能不适用于某些老版本vscode。
使用npx eslint --init 进行快速配置
- 添加ts相关配置在.eslintrc.js文件中
-
parserOptions: { project: ["./tsconfig.json"], // 告诉 eslint:tsconfig 在哪 }
-
配置一些rules后,eslint控制台无报错就运行正常了。
-
-
-
开发npm包(*)
-
-
目前开发npm包使用rollup来打包更好,冗余代码较少。不过webpack也可以用于打包npm包,基本上各种格式的输出都支持。