代码地址 github.com/Maricaya/ad… , 有帮助请 star ~css
刚接触 react 的时候,你们都是经过 create-react-app 等脚手架来快速建立应用。当基本配置知足不了咱们的特殊需求时(好比使用 sass),咱们会修改 eject 出来的 webpack 配置文件。html
面对各类配置项一脸懵逼,不知道怎么快速修改。其实,学习项目搭建与配置没有什么技巧,都是经验(套路)。前端
这篇文章会介绍使用 webpack 手动搭建一个 react 项目的套路,来看看个人踩坑经历吧。node
npm init -y
复制代码
这一步建立 package.jsonreact
打开 webpack 官网,找到安装命令。linux
yarn add webpack webpack-cli typescript --dev
yarn add react react-dom
yarn add @types/react @types/react-dom --dev
复制代码
在这个文件中写入几行 TypeScript 代码。webpack
console.log(123);
复制代码
index.tsx 在浏览器中是不能运行的,须要 webpack 帮咱们打包成浏览器可执行的 index.js。git
在根目录新建 webpack.config.js。程序员
如下配置都写在 module.export 对象内部。github
module.export = {}
复制代码
mode 是 webpack 4 中新增长的选项, 有两个可选值:production(生产环境)和 development(开发环境)。 mode 不可省略。 咱们先配置成开发环境,后面有须要再修改。
mode: 'development'
复制代码
打包的入口文件。
entry: {
<key>: <value> } 复制代码
在这里只介绍对象形式,是由于这个是最完整的entry配置,其余形式只是它的简化而已。
对象中的每一对属性对,都表明着一个入口文件。所以多页面配置时,确定是这种形式的 entry。
key 能够是字符串变量,对应输出文件的名称;也能够是路径,好比 'a/b/c',对应着文件的输出路径。 详细解释能够看这篇文章。
entry: {
index: './lib/index.tsx' // ./ 当前目录下
}
复制代码
webpack在启动后会从配置的入口模块触发找出全部依赖的模块, resolve 配置 webpack 如何寻找模块对应的文件。
在导入语句没带文件后缀时,webpack 会自动带上后缀去尝试访问文件是否存在。 resolve.extensions 用于配置在尝试过程当中用到的后缀列表。
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
}
复制代码
接下来配置解释 tsx 的 loader。那么问题来了,怎么知道哪些是最合适的 loader?
答案是没有标准 loader,只能是一个一个试。
把网上能找到的配置方式所有试一遍以后,我找到一个我认为最好的方式 awesome-typescript-loader
。
安装
yarn add awesome-typescript-loader --dev
复制代码
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'awesome-typescript-loader'
}
]
}
复制代码
再配置翻译 scss 的模块,须要使用三个 loader,style-loader, css-loader,sass-loader
yarn add --dev style-loader css-loader sass-loader
复制代码
能够看出 webpack 中 loader 的原则,一个loader只作一件事情
<style>css</style>
{
test: /\.s([ac])ss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}
复制代码
配置完了输入、中间 loader,接下来咱们来配置输出 output。
path 输出地址 我原本觉得这里能够直接写绝对路径__dirname + './dist'
,后来发如今 windows 上会报错。 由于在不一样的操做系统上,路径表示方法不同。
__dirname + '\\dist'
,__dirname + './dist'
。因此,咱们直接使用 node.js 提供的方法 path.resolve(__dirname, 'dist')
, 这个 API 会根据操做系统的类型将两个目录链接起来。
library: 'adorable-react'
开发 npm 包的时候会用到这个命令,library 是指定用户使用require时的模块名。 这个模块在使用时,命令是 require("adorable-react")
。
libraryTarget 表示库的输出格式是什么,输出模块规范。有这么几种选择 umd、amd、commonjs2。
通常都选 'umd',一种在全部模块定义下均可运行的方案。
下面问题来了,umd 究竟是什么呢?
要知道 umd 是什么,咱们须要先了解下前端打包的历史。
前端最开始是没有包管理系统的,全部的js代码都经过 script 标签一个一个加载。 这个阶段 js 包内重名的全局变量会互相影响。这时就须要打包工具,把变量做用域限制在局部。
前端程序员提出了 AMD 打包方案,Node.js 社区也提出了另外一套打包规则 commonJS。
define (function () {
// 这里是咱们的变量
var a = 1 ...
})
复制代码
这个标准叫作 amd 异步模块定义。
var a = 1 // 只在当前文件有效
module.exports = { ... }
复制代码
咱们正在写的 webpack.config.js 也遵循这个规范。
commonJS 只在 Node.js 中使用,AMD 只在浏览器中使用。 致使你在使用时,必须区分代码是运行在客户端仍是服务端。
这时,有人发明了一套统一的规则 UMD 统一模块定义。 UMD 会判断当前运行环境是什么,根据运行环境选择使用 commonJS 或者 AMD。
因此在这里,咱们选择最完整的 UMD。
最后,完整的 output 代码以下:
const path = require('path')
// mo
output: {
path: path.resolve(__dirname, 'dist/lib'),
- library: 'adorable-react',
libraryTarget: 'umd'
}
复制代码
在根目录下建立 tsconfig.json,它是 TypeScript 的配置文件。
主要包含两块内容:
咱们这篇文章主要讲 webpack 4.0 的配置,ts 的配置文件先略过,能够直接拷贝个人仓库里 tsconfig.json 文件。
配置完这些基本规则以后,咱们能够尝试用 npx webpack
打包啦。
打包后的文件是这样的:
根目录/dist/lib/index.js
— 这是 index.tsx 翻译以后的文件
根目录/lib/index.d.ts
— 包含了声明的全部类型
index.d.ts 放置的目录不对,生成的 *.d.ts 类型文件都应该放入dist目录中。
一顿搜索后,我在 tsconfig.json "compilerOptions"
中配置 "outDir": "dist"
。
再次打包,全部文件都放进了 dist 目录,第一次用 webpack 打包就完成啦。
目前 webpack 就作了一件事,把 ts、tsx 翻译成 js。
接下来咱们安装 webpack-dev-server,让代码可以自动编译,实现热更新。
yarn add webpack-dev-server --dev
npx webpack-dev-server
复制代码
此时,访问 http://localhost:8080/index.js 咱们能够看到编译后的文件。
随意改动 lib/index.tsx
中的文件,http://localhost:8080/index.js 会自动更新。
那么问题来了,webpack-dev-server 为何编译这么快?什么是热更新?
整个的过程咱们能够简化一下,webpack-dev-server 会启动一个小型服务器(称为 Bundle Server)。
Bundle Server就是一个服务器,会执行这些编译后的文件,让浏览器能够访问到。
webpack 打包好的文件 index.js 会传输给 Bundle Server,放在内存中,
等用户访问 index.tsx 时,服务器直接从内存中抛出index.js,因此编译很快。
在应用程序的开发环境,方便开发人员在不刷新页面的状况下,就能修改代码, 而且直观地在页面上看到变化的机制。
到目前为止,我尚未 html 文件,在根目录新建 html 入口文件 index.html。
下面问题来了,引入 js 的文件路径是什么?
只要 entry 下的文件名称修改,咱们就须要手动修改 js 的路径。那为何不自动生成路径呢?
安装插件 html-webpack-plugin
,根目录建立 index.html 文件,把 webpack 打包后的静态文件自动插入到 html 中。
yarn add --dev html-webpack-plugin
复制代码
webpack.config.js 配置
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
new HtmlWebpackPlugin({
title: "adorable-react", // 页面 title
template: "index.html"
})
],
复制代码
把 index.tsx 的 ReactDom 挂载到 index.html 上。 index.tsx 中:
const div = document.createElement('div');
div.innerText = 'div';
document.body.appendChild(div);
复制代码
若是咱们想引用一个库,可是又不想让webpack打包, 能够经过配置 externals 实现。
这个功能主要用在,建立一个 npm 库的时候。
好比:咱们开发了一个 React 的组件库,里面引用了 react 和 react-dom。 可是咱们不必把 react 和 react-dom 打包起来,由于用户会在使用时会本身下载。
那么咱们就能够 externals 的方式,将 react/react-dom 从咱们的源代码中排出去。
externals: {
// 配置如何引入
react: {
// 运行在 Node.js 环境中,import * as React from 'react' 等价于 const react = require('react')
commonjs: 'react',
commonjs2: 'react',
// 使用require.js等加载,等价于 define(["react"], factory);
amd: 'react',
//在浏览器中使用,须要提供一个全局的变量'React',等价于 var React = (window.React) or (React);
root: 'React'
},
'react-dom': {
commonjs: 'react-dom',
commonjs2: 'react-dom',
amd: 'react-dom',
root: 'ReactDom'
}
}
复制代码
看到这里,你已经完成了 webpack 全部基本配置!给本身鼓鼓掌吧!
不过目前 develop 模式和 production 模式都写在一块儿,难道每次打包都须要手动修改吗?
别急,webpack 为咱们提供了自动切换方式。
将 webpack 文件分为 develop 模式和 production 模式,公共部分写入 webpack.config.js。
develop 写入 webpack.config.prod.js,production 写入 webpack.config.dev.js。
完整写法能够点击连接查看,这里这给出核心代码: webpack.config.prod.js
const base = require('./webpack.config')
// 使用 Object.assign
module.exports = Object.assign({}, base,{
mode: 'production'
})
复制代码
咱们在 package.json scripts 中配置好命令,直接使用 yarn xxx
就能够运行项目。
直接看最后的命令:
{
"script": {
"start": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.dev.js",
"build": "cross-env NODE_ENV=production webpack --config webpack.config.prod.js"
}
}
复制代码
开发模式命令 webpack-dev-server
,webpack 的配置是 webpack.config.dev.js
。 生产模式命令 webpack
,webpack 的配置是 webpack.config.prod.js
。
NODE_ENV=development
是咱们写入的环境变量。
你可能也有这个疑问,webpack.dev.config.js 中不是有 mode 吗? 为何要手动写入环境变量?
由于 webpack 处理的这个入口脚本文件及其引用的脚本文件都没法访问 webpack.dev.config.js 的属性, 因此手动写入环境变量,让全部文件能够访问到 process.env.NODE_ENV。
cross-env 插件的做用是:保证环境变量在各个平台都能添加成功。(在 unix、windows 上环境变量写法不同)
安装方式
yarn add --dev cross-env
复制代码
引入 react 社区最流行的测试框架 jest,官网
测试配置不是重点,你们能够直接看仓库
这里简单说下配置:
yarn add --dev jest babel-jest @babel/preset-env @babel/preset-react react-test-renderer
yarn add --dev ts-jest
复制代码
建立 .babelrc
{ "presets": ["react-app"] }
复制代码
配置 scripts test
"test": "cross-env NODE_ENV=test jest --config=jest.config.js --runInBand"
复制代码
配置 Enzyme Enzyme 是用于 React 的 JavaScript 测试实用程序,能够更轻松地测试 React 组件。
yarn add --dev enzyme enzyme-adapter-react-16
复制代码
建立 test 文件夹,写入配置,这里不赘述了,有兴趣直接看源码吧~
终于完成了项目搭建,最后来看看每一个目录的做用吧!
如今每一个文件的功能咱们都很是清楚,出了问题,咱们也知道应该在哪里修改。
.
├── .babelrc // babel 配置
├── README.md
├── index.html // 首页
├── jest.config.js // jest 配置
├── dist // 最终代码
├── lib // 源代码
│ ├── __tests__
│ │ └── index.unit.tsx
│ ├── index.scss
│ └── index.tsx
├── package.json
├── test // test 配置
│ ├── __mocks__
│ │ ├── file-mock.js
│ │ └── object-mock.js
│ └── setupTests.js
├── tsconfig.json // ts 配置
├── tsconfig.test.json // ts 测试配置
├── tslint.json // 代码检测配置
├── webpack.config.dev.js // webpack 配置
├── webpack.config.js
├── webpack.config.prod.js
├── webpack.config.wheel.js
└── yarn.lock
复制代码
恭喜你完成了项目搭建,接下来咱们能够愉快地 coding 了!