在这以前,每开始一个新项目我都是使用现有的脚手架,这很是便于快速地启动一个新项目,并且通用的脚手架一般考虑地更加全面,也有利于项目的稳定开发;不过对于一个小项目,根据需求本身搭建可能会更好,一方面小项目不须要脚手架那么丰富的功能,另外一方面能够提升对项目的掌控度以方便后期的扩展。javascript
这篇文章是在实践中总结的,具备实操性,读者可跟着一步步进行搭建,中间我会穿插一些原理,固然由于笔者的能力有限,不会特别深刻。css
预备知识html
目标java
这有点老生常谈了,不过为了新同窗可以看下去,在这里简单介绍一下。一个现代化的web应用,已经不是单纯地优html、css、javascript组成的,它还须要对应用进行打包、压缩和编译成浏览器可以理解的代码,因而webpack就开始流行起来了。node
webpack是一个模块打包器,它能够打包任何东西。你能够在开发时使用最新的Javascript特性或Typescirpt,webpack会将它编译成浏览器支持的代码并压缩它;你还能够在Javascript中导入须要用到的静态资源。react
在开发过程当中,webpack提供了开发服务器并支持HMR,什么是HMR和怎么配置后面会详细介绍,如今咱们只要知道当咱们保存代码的时候webpack会帮咱们自动从新编译和刷新浏览器。webpack
webpack的能作的远不止这些,这篇文章主要是帮助你熟悉基本概念和如何去配置本身的脚手架。es6
这篇文章算是一个较为完整的实战教程,目标是搭建一个可用的脚手架,在此基础上能够扩展出更多的功能。web
架构须要支持的特性typescript
Webpack5
命令行友好提示
es6+
React
Typescript
PostCSS + cssnext
HMR
新建一个项目,进入项目根目录,建立默认的package.json
yarn init -y
复制代码
安装webpack
和webpack-cli
webpack
- 模块打包库webpack-cli
- 命令行工具yarn add webpack webpack-cli -D
复制代码
在根目录下新建一个webpack.config.js
Entry
入口文件,webpack会首先从这里开始编译
// webpack.config.js
const path = require('path');
module.exports = {
entry: {
app: './src/index.js'
},
}
复制代码
Output
定义了打包后输出的位置,以及对应的文件名。[name]
是一个占位符,这里是根据咱们在entry
中定义的key值,即等价于app
module.exports = {
/* ... */
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',
},
}
复制代码
确保src下有index.js,而后如今可使用咱们的最小化配置进行打包。在package.json
中加入如下代码
"scripts": {
"build": "webpack"
}
复制代码
运行该命令
yarn run build
复制代码
能够在命令行中看到打包的结果,而且在根目录下生成了一个dist目录,说明打包成功。
插件使webpack具有可扩展性,可让咱们支持更多的功能。
模板文件
当咱们构建一个web app的时候,咱们须要一个HTML页,而后再HTML中引入Javascript,当咱们配置了打包输出的bundle文件是随机字符串时,每次手动更新就特别麻烦,因此最好的方法是能够自动将bundle打包进HTML中。
安装
yarn add html-webpack-plugin -D
复制代码
在根目录下新建一个文件public/index.html
,内容以下
<!DOCTYPE html>
<html lang="en">
<head>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="root"></div>
</body>
</html>
复制代码
其中title是读取html-webpack-plugin
插件的配置,配置以下
// webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
/* ... */
plugins: [
new HtmlWebpackPlugin({
title: '铁木真大屏展现',
template: path.resolve(__dirname, './public/index.html'),
filename: 'index.html',
}),
],
}
复制代码
如今咱们再次运行yarn run build
,能够看到dist
下多了一个index.html
,其中自动插入了标题和script,效果以下
打包前清除dist
clean-webpack-plugin
- 打包前移除/清理 打包目录安装
yarn add clean-webpack-plugin -D
复制代码
配置
const path = require('path')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
/* ... */
plugins: [
/* ... */
new CleanWebpackPlugin(),
],
}
复制代码
命令行友好提示
安装
yarn add friendly-errors-webpack-plugin -D
复制代码
配置
// webpack.config.js
const friendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
module.exports = {
plugins: [
new friendlyErrorsWebpackPlugin(),
]
}
复制代码
webpack使用loaders去解析模块,webpack想要去如何理解Javascript、静态资源(图片、字体、css)、转移Typescript和Babel,都须要配置相应的loader规则。
在项目中只有一个HTML和一些Javascript是没什么用的,咱们还须要webpack可以作一些事:
Babel
Babel 是一个 JavaScript 编译器,能将 ES6 代码转为 ES5 代码,让你使用最新的语言特性而不用担忧兼容性问题,而且能够经过插件机制根据需求灵活的扩展,咱们须要先安装如下库
yarn add babel-loader @babel/core -D
复制代码
babel-loader
- 使用Babel和webpack转译文件@babel/core
- 转译ES2015+的代码配置以下
// webpack.config.js
module.exports = {
/* ... */
module: {
rules: [
// JavaScript
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
}
复制代码
在 Babel 执行编译的过程当中,会从项目根目录下的配置文件读取配置。在根目录下建立Babel的配置文件babel.config.json
{
"presets": ["@babel/preset-env"]
}
复制代码
若是未安装@babel/preset-env
须要先安装
yarn add @babel/preset-env -D
复制代码
图片和字体
解析图片的loader配置
module.exports = {
/* ... */
module: {
rules: [
// Images
{
test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
type: 'asset/resource',
},
],
},
}
复制代码
解析字体文件的loader配置
module.exports = {
/* ... */
module: {
rules: [
// Fonts and SVGs
{
test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
type: 'asset/inline',
},
],
},
}
复制代码
样式
如今咱们但愿可以在Javascript中导入CSS,以及将CSS注入DOM,另外还想使用CSS的高级特性,如cssnext,须要依赖一下库
css-loader
- 解析CSS导入
style-loader
- 将CSS注入DOM
postcss-loader
- 用PostCSS处理CSS
postcss-preset-env
- PostCSS的默认配置postcss
- PostCSS 是一个容许使用 JS 插件转换样式的工具。 这些插件能够检查(lint)你的 CSS,支持 CSS Variables 和 Mixins, 编译还没有被浏览器普遍支持的先进的 CSS 语法,内联图片,以及其它不少优秀的功能。
postcss-next
- PostCSS的插件,可使用CSS最新的语法
安装
yarn add css-loader style-loader postcss-loader postcss-preset-env postcss postcss-cssnext -D
复制代码
新建PostCSS配置文件postcss.config.js
,配置以下
module.exports = {
plugins: {
'postcss-preset-env': {
browsers: 'last 2 versions',
},
},
}
复制代码
配置loader
// webpack.config.js
module.exports = {
/* ... */
module: {
rules: [
// CSS, PostCSS, and Sass
{
test: /\.(scss|css)$/,
use: ['style-loader', {
loader: 'css-loader',
options: {
importLoaders: 1,
},
}, 'postcss-loader'],
},
],
},
}
复制代码
让咱们从设置配置为开发模式开始,表示当前的配置的配置为开发环境的配置
// webpack.config.js
module.exports = {
mode: 'development',
// ...
}
复制代码
使用source maps
为了在报错的时候更好的追踪代码和给出错误代码出现的地方的提示,咱们可使用source map
,配置以下
// webpack.config.js
module.exports = {
devtool: 'inline-source-map'
// ...
}
复制代码
HMR
当咱们改动代码时,但愿能自动从新编译代码,webpack提供了三种不一样的方式:
大多数状况,使用的是webpack-dev-server
,本文也是使用这个,不过我会顺带介绍一下其它两种方式,你们各取所需。
// package.json
{
"watch": "webpack --watch"
}
复制代码
执行如下命令
yarn run watch
复制代码
如今当咱们保存代码的时候会自动编译代码,刷新浏览器后便可看到效果;可是咱们想要自动刷新浏览器怎么办,这时候就轮到webpack-dev-server
商场了。
它为咱们提供了一个服务器和live relaoding
的能力,咱们须要首先安装它
yarn add webpack-dev-server -D
复制代码
而后配置以下
// webpack.config.js
module.exports = {
// ...
devServer: {
historyApiFallback: true,
contentBase: path.join(__dirname, './dist'),
open: false,
hot: true,
quiet: true,
port: 8082,
},
}
复制代码
// package.json
{
"scripts": {
"start": "webpack serve"
}
}
复制代码
咱们在8082端口监听了一个服务,监听的目录是dist
,而且支持HMR,如今打开http://localhost:8082
,能够看到咱们的页面,而后改动代码,浏览器会自动刷新更新效果,是否是很酷!
上面提到了HMR,它的全称是Hot Module Replacement,翻译过来就是热模块替换,我认为它是webpack提供的最有用的一个特性,它容许咱们只更新改动过的模块,而不需有所有更新,咱们在上面已经开启了该功能,即hot: true
。
这是一个webpack的中间件,可让webpack把文件交给一个服务器处理,好比接下来要使用的express
,这给了咱们更多的控制权,接下来简单演示一下。
安装express
和webpack-dev-middleware
yarn add express webpack-dev-middleware -D
复制代码
更改配置
module.exports = {
//...
output: {
//...
publicPath: '/'
}
}
复制代码
publicPath
能够定义了express监听服务的路径,接下来就建立咱们的
express`服务器
新建一个server.js
const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);
// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
app.use(
webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath,
})
);
// Serve the files on port 3000.
app.listen(3000, function () {
console.log('Example app listening on port 3000!\n');
});
复制代码
监听端口为3000,执行如下命令启动服务
node server.js
复制代码
方便起见,能够将该命令加入package.json
{
//...
"scripts": {
"server": "node server.js"
}
}
复制代码
安装依赖
yarn add typescript ts-loader -D
复制代码
在根目录下建立typescript
的配置文件tsconfig.json
,具体配置以下
{
"compilerOptions": {
"outDir": "./dist/",
// "rootDir": "./src",
"sourceMap": true, // 开启sourcemap
"module": "commonjs",
"target": "es5",
"jsx": "react",
"esModuleInterop": true,
"allowJs": true,
"strict": true
}
}
复制代码
// webpack.config.js
module.exports = {
//...
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
]
}
}
复制代码
在上面配置typescript
中,已经开启了支持react,如今只需安装react的依赖便可
yarn add react react-dom @types/react @types/react-dom
复制代码
而后将入口文件改为.tsx
后缀,内容以下
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
const App = () => {
return <div>hello world2</div>;
};
ReactDOM.render(<App />, document.getElementById('root'));
复制代码
Prettier是一个诞生于2016年就迅速流行起来的专一于代码格式化的工具。出道即巅峰啊-.- Prettier
只关注格式化,并不具备lint检查语法等能力。它经过解析代码并匹配本身的一套规则,来强制执行一致的代码展现格式。 它在美化代码方面有很大的优点,配合ESLint能够对ESLint格式化基础上作一个很好的补充。
使用
以VSCode为例,安装Prettier插件便可使用,若是想自定义配置,能够cmd+,
快捷键进入vscode配置,搜索Prettier找到对应的配置项进行配置。
ESLint 是一个在 JavaScript 代码中经过规则模式匹配做代码识别和报告的插件化的检测工具,它的目的是保证代码规范的一致性和及时发现代码问题、提早避免错误发生。 ESLint 的关注点是代码质量,检查代码风格而且会提示不符合风格规范的代码。除此以外 ESLint 也具备一部分代码格式化的功能。
安装依赖,方便起见,直接使用已有的Eslint配置,这里使用的是fabric
yarn add @umijs/fabric -D
复制代码
根目录下新建.eslintrc.js
,配置以下
module.exports = {
extends: [require.resolve('@umijs/fabric/dist/eslint')],
globals: {},
plugins: ['react-hooks'],
rules: {
'no-restricted-syntax': 0,
'no-param-reassign': 0,
'no-unused-expressions': 0,
},
};
复制代码
重启编辑器,便可应用Eslint的配置。
到目前为止,咱们搭建了一个简易的react脚手架,而且它支持typescript
、cssnext
、HMR等特性,对于一个小项目来讲已经足够用了,你们能够在此基础上进行扩展;后面有时间的话会和你们一块儿讨论一下webpack稍底层的原理,是从源码的角度去看。