一、PostCSS 与 CSS 模块
PostCSS 是一个用 JavaScript 工具和插件转换 CSS 代码的工具。比如可以使用
Autoprefixer插件自动获取浏览器的流行度和能够支持的属性,并根据这些数据帮我们自动地为 CSS 规则添加前缀,将最新的 CSS 语法转换成大多数浏览器都能理解的语法。CSS 模块 能让你永远不用担心命名太大众化而造成冲突,只要用最有意义的名字就行了。
1. PostCSS
在 Webpack 中使用 PostCSS,需要安装 style-loader、css-loader、postcss-loader:
npm i style-loader css-loader postcss-loader -D
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: ['style-loader', 'css-loader', 'postcss-loader']
}
]
}
}
创建 postcss.config.js:
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer'),
require('postcss-nested')
]
}
- 插件
autoprefixer提供自动给样式加前缀去兼容浏览器 - 插件
postcss-nested提供编写嵌套的样式语法
// package.json
"browserslist": [
"> 1%",
"last 2 versions"
]
last 2 versions:表示每个浏览器中最新的两个版本;> 1%或者>= 1%:表示全球浏览器使用率大于 1% 或大于等于 1%。
2. CSS 模块
使用 CSS 模块可以解决多人编写的样式可能会冲突的问题。
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true // 开启 css 模块
}
},
'postcss-loader'
]
}
]
}
}
假如有样式文件:
/* style.css */
body {
display: flex;
flex-direction: column;
.box {
width: 100px;
height: 100px;
background: red;
}
}
在 js 文件里导入 css 文件:
import style from './style.css' // 开启 css 模块后,可以导入模块
const div = document.createElement('div')
div.textContent = 'hello webpack'
div.classList.add(style.box) // style 里可以识别 class 样式
document.body.appendChild(div)
二、Web Works
有时我们需要在客户端进行大量的运算,但又不想让它阻塞我们的 js 主线程,你可能第一时间考虑到的是异步。但事实上,运算量过大(执行时间过长)的异步也会阻塞 js 事件循环,甚至会导致浏览器假死状态。
这时,HTML5 的新特性 WebWorker 就派上了用场。
HTML5 以前,打开一个常规的网页,浏览器一般至少存在三个线程(公用线程不计入在内):分别是 js 引擎线程(处理 js)、GUI 渲染线程(渲染页面)、浏览器事件触发线程(控制交互)。
当一段 JS 脚本长时间占用着处理机,就会挂起浏览器的 GUI 更新,而后面的事件响应也被排在队列中得不到处理,从而造成了浏览器被锁定进入假死状态。
现在如果遇到了这种情况,我们可以做的不仅仅是优化代码,还可以使用 HTML5 提供的 WebWorker。
WebWorker 提供了 js 的后台处理线程的 API,它允许将复杂耗时的单纯 js 逻辑处理放在浏览器后台线程中进行处理,让 js 线程不阻塞 UI 线程的渲染,多个线程间可以通过相同的方法进行数据传递。
// new Worker(scriptURL: string | URL, options?: WorkerOptions)
new Worker("someWorker.js")
也就是说,需要单独写一个 js 脚本,然后使用 new Worker 来创建一个 Work 线程实例。这意味着并不是将这个脚本当做一个模块引入进来,而是单独开一个线程去执行这个脚本。
常规模式下,Webpack 只会打包出一个 bundle.js,那我们的 worker 脚本怎么办?Webpack4 的时候就提供了 worker-loader 专门配置 WebWorker,但在 Webpack5 中,已经内置了这个功能。
示例:
// work.js
self.onmessage = (message) => {
self.postMessage({
answer: 1111
})
}
// app.js
// import.meta.url 参数能够锁定当前的这个模块,注意,它不能在 CommonJS 中使用
const worker = new Worker(new URL('./work.js', import.meta.url))
worker.postMessage({
question: 'hi,那边的workder线程,请告诉我今天的幸运数字是多少?'
})
worker.onmessage = (message) => {
console.log(message.data.answer)
}
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/app.js',
plugins: [
new HtmlWebpackPlugin()
]
}
运行 npx webpack,发现 dist 目录中除了 main.js,还有一个 src_work_js.js,这说明 Webpack5 自动的将被 new Worker() 使用的脚本单独打出了一个 bundle。
三、TypeScript
1. 在 Webpack 工程化环境中集成 TS
- 安装
typescript和ts-loader
npm install --save-dev typescript ts-loader
- 添加 ts 配置文件(tsconfig.json):
npx tsc --init
- 生成的 tsconfig.json 中注释了很多配置,可以根据想要的效果打开对应的配置,如:
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"rootDir": "./src",
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
- 新增一个 src/app.ts:
// app.ts
const age: Number = 18
console.log(age)
- 配置 webpack.config.js:
// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/app.ts',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: 'ts-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin()
],
devtool: 'inline-source-map',
resolve: {
extensions: ['.ts', '.js']
},
}
2. 在 TypeScript 中使用第三方类库
安装第三方库时,要同时安装这个库的类型声明文件。以 lodash 为例:
npm i lodash
npm i @types/lodash --save-dev
可以从 Type Search 中找到对应的类型声明文件。