从零开始,慢慢更新,慢慢探索~~~
简单的demo
我们先从一个简单的demo来看看具体的流程:
初始化
执行 npm init 创建一个符合node规范的项目,创建之后会成一个package.json项目。
{
"name": "tsdemo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
},
"author": "",
"license": "ISC",
}
react
-
执行
npm i react react-dom安装react和react-dom。 -
创建页面:
// ***src/App.tsx***
import React from 'react';
const App: React.FC = () => {
return (<div>hello, world</div>);
};
export default App;
// ***src/index.tsx***
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
// ***src/index.html***
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
<title>react-app</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
typescript
-
执行
npm i typescript -D安装typescript -
创建配置文件:
// tsconfig.json
{
"compilerOptions": {
"outDir": "./dist", // 输出的目录
"module": "CommonJS", // 指定生成哪个模块系统代码: "None", "CommonJS", "AMD", "System", "UMD", "ES6"或 "ES2015"
"target": "ES2015", // 指定 ES 目标版本,默认 ES3
"jsx": "react", // 在 .tsx 文件里支持 jsx
"declaration": true, // 生成相应的 .d.ts 文件
"removeComments": true, // 删除所有注释,除了以 /!* 开头的版权信息。
},
"include": [
"src/**/*", // 需要编译的文件
],
"exclude": [
"node_modules", // 不编译此文件夹下的文件
],
}
webpack
- 执行
npm install webpack webpack-cli -S -D
webpack 用来打包,webpack-cli 让 webpack 命令可以执行
-
项目中有
.tsx文件,所以要安装loader进行处理:执行npm install ts-loader --save-dev安装ts-loader对.tsx文件进行打包。并进行如下配置。 -
创建配置文件:
// ***webpack.config.js***
const path = require('path')
module.exports = {
mode: 'development', // 模式,当前为开发模式,还有个生产模式,生产模式会自动压缩编译后代码到一行
entry: './src/index.tsx',
module: {
rules: [
{
test: /\.tsx?$/, // ts-loader是官方提供的处理tsx的文件
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve:{
// 打包的时候报错:Module not found :Error : can't resolve 'App'
// 我们引入组件的时候,并没有加后缀(.tsx),
// 此配置会按顺序为我们找App.js App.jsx...找到就返回,找不到会报错
extensions: ['.js', '.jsx', '.ts', '.tsx', '.css', '.less', '.scss']
},
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'dist')
}
}
配置
最后在package.json文件中,配置如下
{
"name": "tsdemo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack" // 执行 npm run build 相当于 npx webpack
},
"author": "",
"license": "ISC",
"dependencies": {
"react": "^17.0.1",
"react-dom": "^17.0.1"
},
"devDependencies": {
"ts-loader": "^8.0.14",
"typescript": "^4.1.3",
"webpack": "^5.15.0",
"webpack-cli": "^4.3.1"
}
}
之后执行npm run build,就可以看到dist文件下打包好的文件。一个小的demo就完成了。
plugin
经过上边的一些列操作之后,我们看到了dist下打包好的文件,但是并没有看到页面。可以在 vscode 中安装插件 open in browser ,之后在 index.html 中右击选中 open in default browser,就可以看到浏览器中出现了html页面。
但是存在一个新的问题:并没有显示 App 组件中的东西(hello world)。
我们需要在 index.html中引入打包好的文件(bundle.js):
<script src="../dist/bundle.js"></script>
删除掉dist文件夹,从新打包 npm run build。
你会发现依旧没有任何东西,打开控制台,会报错:
Cannot read property 'createElement' of undefined
Consider adding an error boundary to your tree to customize error handling behavior.
这是因为 react 和 react-dom 引入不规范导致的,将所有引入改为:
import * as React from 'react'
import * as ReactDom from 'react-dom'
前边的过程中,存在三个问题:
- 每次打包都要手动删除
dist文件夹 - 手动添加打包后的
bundle.js文件 html页面并没有跑在localhost上,并且需要手动打开
接下来就逐步解决这些问题。
clean-webpack-plugin
clean-webpack-plugin 的作用是在打包之前删除output.path下的所有内容之后再进行打包。所以不用传递参数。
-
安装 :
npm install --save-dev clean-webpack-plugin -
引入并配置:
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
plugins:[
new CleanWebpackPlugin()
],
}
这样就不用每次打包前手动删除dist文件夹了。
html-webpack-plugin
自行点击标题进入官网按照教程下载就好。
HtmlWebpackPlugin的作用是当打包完成时,以src/index.html文件为模板,生成index.html文件,并将打包好的js文件注入到里边。
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins:[
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
}
打包后你会看到dist下会有个html文件。并且将打包好的bundle.js文件自动添加。打开这个HTML,我们可以看到正常的页面。这样我们就不用逐个把打包后的文件添加到HTML文件中(所入口打包的话可能会产生很多打包后的文件,逐个添加很麻烦)。
webpack-dev-server
看官网自行安装。
module.exports = {
devServer:{
contentBase:'./dist', //借助devServer生成服务器放到dist目录下,但是dist目录下看不到任何东西,在内存中,这样可以提升速度
open:true, //可以自动打开网址不必手动打开
},
}
配置命令:
"scripts": {
"build": "webpack",
"start": "webpack serve"
// "start": "webpack-dev-server"
// 报错Error: Cannot find module 'webpack-cli/bin/config-yargs'
// code: 'MODULE_NOT_FOUND'
},
运行 npm run start你会发现浏览器会自动打开窗口,并且当你修改完代码的啥时候,网页自动刷新。
loader
.jsx文件
执行npm install -D babel-loader @babel/core @babel/preset-env @babel/preset-react
根目录创建.babelrc文件并配置:
{
"presets": ["@babel/preset-react","@babel/preset-env"]
}
配置webpack:
module:{
rules:[
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {loader: "babel-loader"}
}
]
}
.css文件
安装style-loader : npm install --save-dev style-loader
安装css-loader :npm install --save-dev css-loader
配置如下:
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'], //?modules 打开css-modules
},
css-loader负责分析各个文件之间的关系,将不同文件的代码生成一个代码块。style-loader负责将css-loader生成的代码块挂载到head中。所以loader使用顺序是从右向左,从下向上。
.less文件
安装npm i style-loader css-loader less-loader less -D
配置:
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
其中less-loader就是将less语法转化为css语法,之后就和css做一样的处理。
babel
我们代码中经常会用到es6语法,但是低版本的浏览器并不支持es6,需要将其转化为es5。
可以去babel官网详细的了解下。
我们主要使用到的是babel-loader,bable/core还有babel/preset-env前边我们已经安装过。
接下来就是在配置文件中配置:
rules: [
{ test: /\.(js|jsx)$/,, // 以js和jsx结尾的文件
exclude: /node_modules/, //文件不在node_modules文件夹下
loader: "babel-loader" , //babel是js和babel的桥梁,但是并不完成代码转化
options:{
"presets": ["@babel/preset-env"] //代码转化
}
},
]
低版本的浏览器中不存在某些es6的对象,比如map之类的。这时候需要将这些不存在的函数或者对象补充到浏览器中。可能会想到babelPolyfill 但是他在注入的时候很多东西都是全局注入的。所以我们用plugin-transform-runtime
plugin-transform-runtime
安装npm install --save-dev @babel/plugin-transform-runtime 和 npm install --save @babel/runtime 以及 npm install --save @babel/runtime-corejs2
配置如下:
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
"presets": ["@babel/preset-env"] //代码转化
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 2,
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
]
}
},
babel-loader配置项options里面的内容可以单独抽出来放到根目录下.babelrc
.babelrc文件配置babel
{
"presets": [
"@babel/preset-react",//之前配置.jsx文件添加的
"@babel/preset-env"
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 2,
"helpers": true,
"regenerator": true,
"useESModules": false
}
]
]
}
antd
执行npm install antd --save安装。
首先如果会使用到icon需要先安装:npm install --save @ant-design/icons
- 报错
Support for the experimental syntax 'classProperties' isn't currently enable
解决:
npm install --save-dev @babel/plugin-proposal-class-properties
并配置.babelrc
"plugins": [
"@babel/plugin-proposal-class-properties",
]
- 报错:缺少处理
css的loader:
npm install --save-dev css-loader
npm install --save-dev style-loader
并配置:
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
在这个过程中,css-loader负责分析各个文件之间的关系,将不同文件的代码生成一个代码块。style-loader负责将css-loader生成的代码块挂载到head中。
全局引入样式
在入口文件(index.tsx)中全局引入样式:
import 'antd/dist/antd.css'
在使用组件的地方直接引入组件:
import * as React from 'react';
import {Button} from 'antd'
class Header extends React.Component {
render() {
return (
<div>
<Button type="primary">Primary</Button>
<Button>Default</Button>
<Button type="dashed">Dashed</Button>
<Button type="danger">Danger</Button>
<Button type="link">Link</Button>
</div>
);
}
}
export default Header
局部引入样式
方法一:
入口文件中不再引入样式,在使用组件的页面引入:
import * as React from 'react';
import {Button} from 'antd'
import "antd/lib/button/style" //引入对应的样式
class Header extends React.Component {
render() {
return (
<div>
<div>header</div>
<Button type="primary">Primary</Button>
<Button>Default</Button>
<Button type="dashed">Dashed</Button>
<Button type="danger">Danger</Button>
<Button type="link">Link</Button>
</div>
);
}
}
export default Header
但是这样比较麻烦,每次使用组件都要引入对应的样式文件。
方法二(推荐):babel-plugin-import
安装:npm install babel-plugin-import --save-dev
在.babelrc文件中配置:
"pulgins":[
["import",{"libraryName": "antd","style": true}],
]
使用组件时直接引入组件即可:
import * as React from 'react';
import {Button} from 'antd'
class Header extends React.Component {
render() {
return (
<div>
<div>header</div>
<Button type="primary">Primary</Button>
<Button>Default</Button>
<Button type="dashed">Dashed</Button>
<Button type="danger">Danger</Button>
<Button type="link">Link</Button>
</div>
);
}
}
export default Header
坑坑坑~~~
在这整个过程中,千万要保证没有开启css Modules功能,否则className会被编译,不再是原来样子,导致无论怎么配置,样式都是不起作用的。
css-modules
使css样式只在局部起作用。配置Webpack的css-loader插件,因为它对 CSS Modules 的支持最好,而且很容易使用。
{
test: /\.css$/i,
use: ['style-loader', 'css-loader?modules'],
},
重点是在css-loader后边加上参数 ?modules 打开css modules 功能。打开控制台你可以看到className 被编译成了类似于Cijm8iX5re4lkWOQ2tG-p 的形式。
less
现在我们项目中越来越经常使用less。
安装
执行npm install -g less安装less。
使用
打开css-modules
执行npm i style-loader css-loader less-loader less -D 安装要使用的loader
配置:
{
test: /\.less$/,
use: ['style-loader', 'css-loader?modules', 'less-loader']
}
如果运行时报错:.bezierEasingMixin();将less版本降低到3.0以下,可以安装2.7.3。
第三方库:antd
项目中我使用了组件库antd,这是时候如果开启了css modules会导致引入的样式失效。原因是:css modules会把className编码成类似于_1sNE87DmRAiZ8U-5Rbq8Zn这样的形式,到时第三方库的样式对不上。
为了解决上述问题,我们可以进行如下配置:在node_modules中关闭css modules,在src下开启。
具体配置如下:
{
test: /\.css$/i,
exclude: [/node_modules/], //不包含node_modules文件夹
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true, //开启css-modules模式, 默认值为flase
}
}
],
}, {
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
exclude: [/src/], //不包含src文件夹
},
{
test: /\.less$/,
exclude: [/node_modules/], //不包含node_modules文件夹
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1, //在css-loader前应用的loader的数目, 默认为0
modules: true, //开启css-modules模式, 默认值为flase
}
},
'less-loader'
],
},
{
test: /\.less$/,
exclude: [/src/], //不包含src文件夹
use: ['style-loader', 'css-loader', 'less-loader'],
},
重点就是通过exclude和modules:true进行配置。