大家都不看的总集篇: 从零开始的大前端筑基之旅(深刻浅出,持续更新~)
以为不错就顺手点个赞吧~javascript
写前端一年多了,用的都是大佬建好的架子,还没本身从头建个项目,如今开始踩坑。css
项目大致包括如下几部分html
首先,新建个文件夹basic-react-app
。名字不是重点,你高兴就好。 而后,使用 npm init
初始化项目,依据提示,一路回车下去前端
$basic-react-app npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
// 从这里开始,使用默认的话回车便可
package name: (basic-react-app)
version: (1.0.0)
description: basic react demo
entry point: (index.js)
test command:
git repository:
keywords:
author: suil
license: (ISC)
About to write to /Users/zhangpengcheng15/Documents/code/temp/basic-react-app/package.json:
{
"name": "basic-react-app",
"version": "1.0.0",
"description": "basic react demo",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "suil",
"license": "ISC"
}
Is this OK? (yes)
复制代码
如今,你获得了一个package.json
文件java
而后,使用git init
初始化仓库,能够考虑先在远端初始化仓库,再拉去到本地。node
$basic-react-app git init
Initialized empty Git repository in /Users/zhangpengcheng15/Documents/code/temp/basic-react-app/.git/
$basic-react-app git:(master) ✗
复制代码
若是你使用了特殊的命令窗或zsh,应该就能够看到目录后面显示git:(master)
,表明本地仓库已经建好了。react
别着急下一步,不要忘记配置gitignore
,不然电脑配置很差会卡顿一阵子。
在根目录下新建.gitignore
文件,使用编辑器打开,输入webpack
node_modules
dist
复制代码
并保存。好了,如今仓库初始化结束。ios
最后,打开你喜欢的编辑器,好比 vscode
,来建立以下文件结构。git
.
+ |- /src
+ |- /assets
+ |- /less
+ |- /icons
+ |- /components
+ |- /constants
+ |- /static
+ |- /imgs
+ |- /utils
复制代码
使用
vscode
的同窗,必定要下vscode-icons
插件呀
其中,
好了,文件结构建完成。下面开始安装 react
React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 能够将一些简短、独立的代码片断组合成复杂的 UI 界面,这些代码片断被称做“组件”。
React 认为渲染逻辑本质上与其余 UI 逻辑内在耦合,好比,在 UI 中须要绑定处理事件、在某些时刻状态发生变化时须要通知到 UI,以及须要在 UI 中展现准备好的数据。
React 并无采用将标记与逻辑进行分离到不一样文件这种人为地分离方式,而是经过将两者共同存放在称之为“组件”的松散耦合单元之中,来实现关注点分离。
使用命令行安装 react
及 react-dom
npm install react react-dom
或者 yarn add react react-dom
复制代码
在开始下一步以前,咱们先在目录中添加一些文件。
在src目录下,新建index.tsx
和 index.less
,先不用纠结可否被识别或者运行的问题,下一步咱们再来解决它。
// src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import './index.less'; // 必定要加 './' 表示当前目录下
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
复制代码
h1{
color: blue;
}
复制代码
webpack 是什么
webpack
是一个现代 JavaScript
应用程序的静态模块打包器,当 webpack
处理应用程序时,会递归构建一个依赖关系图,其中包含应用程序须要的每一个模块,而后将这些模块打包成一个或多个 bundle
。
webpack 的核心概念
在本地安装 webpack,接着安装 webpack-cli(此工具用于在命令行中运行 webpack):
npm install webpack webpack-cli --save-dev
复制代码
或者
yarn add webpack webpack-cli --dev
当前webpack基于最新的版本
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11"
复制代码
在 webpack 4 中,能够无须任何配置使用,然而大多数项目会须要很复杂的设置,这就是为何 webpack 仍然要支持 配置文件。
本文目的在于配置一个可用的
react
项目,所以有些配置会一步到位,如需更多webpack知识,请移步 webpack中文网
在根目录建立一个 webpack.config.js
,写入以下内容
const path = require('path');
module.exports = {
entry: './src/index.tsx',
mode: "development",
devtool: 'cheap-module-eval-source-map',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
复制代码
若是 webpack.config.js 存在,则 webpack 命令将默认选择使用它。使用 --config 选项能够传递任何名称的配置文件。
对于多入口文件,可使用以下配置
entry: {
index: './src/index.js',
index2: './src/index2.js',
},
output: {
path: path.resolve(__dirname,'dist'), //此处若非绝对路径,可能报错
filename: '[name].bundle.js',
},
复制代码
在上面的配置文件中,咱们使用了入口 entry
和出口 output
两个概念,相信你也理解这两个配置的含义。后面咱们会用到另外两个概念。
mode 配置项,告知 webpack 使用相应模式的内置优化。
mode 支持如下两个配置:
development:将 process.env.NODE_ENV 的值设置为 development,启用 NamedChunksPlugin 和 NamedModulesPlugin
production:将 process.env.NODE_ENV 的值设置为 production,启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin
简单来讲,*开发环境(development)和生产环境(production)*的构建目标差别很大。将 mode
设置为development
会启用一些webpack默认的优化。这里咱们先设置为 mode: "development",
devtool
中的一些设置,能够帮助咱们将编译后的代码映射回原始源代码。不一样的值会明显影响到构建和从新构建的速度。
对咱们而言,可以定位到源码的行便可,所以,综合构建速度,在开发模式下,devtool
的值设置为cheap-module-eval-source-map
。
其余的配置参数可参考devtool,
Babel 是一个 JavaScript 编译器
ES2015 中的 import 和 export 语句已经被标准化。虽然大多数浏览器还没法支持它们,可是 webpack 却可以提供开箱即用般的支持。
事实上,webpack 在幕后会将代码“转译”,以便旧版本浏览器能够执行。可是注意的是,webpack 不会更改代码中除 import 和 export 语句之外的部分。若是咱们须要使用其它 ES2015 特性,须要在 webpack 的 loader 系统中使用了一个像是 Babel 或 Bublé 的转译器。
Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便可以运行在当前和旧版本的浏览器或其余环境中。下面列出的是 Babel 能为你作的事情:
执行下面的指令安装 babel
系列
yarn add @babel/core @babel/cli @babel/preset-env @babel/preset-react babel-loader --dev
复制代码
其中,
webpack 最出色的功能之一就是,除了 JavaScript,还能够经过 loader 引入任何其余类型的文件。也就是说,以上列出的那些 JavaScript 的优势(例如显式依赖),一样能够用来构建网站或 web 应用程序中的全部非 JavaScript 内容。
如今,在 webpack 配置对象中,添加 babel-loader 到 module 的 loaders 列表中,,当前配置文件以下
module.exports = {
entry: './src/index.tsx',
mode: "development",
devtool: 'cheap-module-eval-source-map',
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
},
],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
复制代码
我下载了那么多包,你就用了这一个?你专门解释的那两个包呢?
不着急,其余的包咱们经过设置babel配置文件来使用。在根目录下新建 .babelrc
文件,输入以下内容
{
"presets": [
"@babel/env",
"@babel/preset-react"
]
}
复制代码
既然说到这里,咱们先还个债,还记得上面新建的 index.tsx
文件么?webpack不认识tsx文件,浏览器也不认识 tsx 文件,那谁来认呢?
固然是babel
了,在7以前的版本中,咱们须要专门的 ts-loader
来转义 ts
和tsx
类型的文件,可是,如今只须要有babel
就够了
不管代码是否具备 ES2015 特性,JSX,TypeScript,仍是其余疯狂的自定义————编译器都知道要作什么。向 ts-loader、ts-jest、ts-karma、create-react-app-typescript 等等说再见就好啦,使用 Babel 代替它们。
yarn add @babel/preset-typescript --dev
复制代码
在.babelrc
文件中补充
{
"presets": [
"@babel/env",
"@babel/preset-react",
+ "@babel/preset-typescript"
],
}
复制代码
好了,到此,ts | tsx 文件可使用babel-loader编译了,记得修改webpack.config.js
文件,补充 ts | tsx
使用babel-loader
编译
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
},
],
复制代码
对于loader的用法,
test
字段是匹配规则,针对符合规则的文件进行处理。
use
字段有几种写法
use: 'babel-loader'
use: ['style-loader', 'css-loader']
use
数组的每一项既能够是字符串也能够是一个对象,当咱们须要在webpack
的配置文件中对 loader
进行配置,就须要将其编写为一个对象,而且在此对象的 options
字段中进行配置,例如上面 babel-loader
可使用另外一种配置形式rules: [
{
test: /\.jsx?$/,
use: {
loader: 'babel-loader',
options: {
presets: ["@babel/preset-env"]
}
},
exclude: /node_modules/
}
]
复制代码
如今,去还另外一个债,less文件。要让webpack识别 less
文件,天然是 less-loader
了。
固然,咱们顺手也补充 css
文件的识别。
有关 less 及 sass 的选择,可移步 Sass.vs.Less | 简介与比较
为了从 JavaScript 模块中 import 一个 CSS 文件,你须要在 module 配置中 安装并添加 style-loader 和 css-loader:
yarn add style-loader css-loader less-loader --dev
复制代码
webpack.config.js
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
},
+ {
+ test: /\.css$/,
+ use: [
+ 'style-loader',
+ 'css-loader'
+ ]
+ },
+ {
+ test: /\.less$/,
+ use: [
+ 'style-loader',
+ 'css-loader',
+ 'less-loader'
+ ]
+ }
],
复制代码
小提示:vscode中,选中
+
号,而后按win + D
,就能够连续选中加号,最后按删除就能够删除全部的+
号
PostCss是一个样式处理工具,它经过自定义的插件和工具生态体系来从新定义css。它鼓励开发者使用规范的css原生语法编写代码,而后配置编译器转换须要兼容的浏览器版本,最后经过编译将源码转换为目标浏览器可用的css代码。
yarn add postcss-loader autoprefixer --dev
复制代码
webpack.config.js
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
+ 'postcss-loader',
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
+ 'postcss-loader',
'less-loader'
]
}
],
复制代码
postcss-loader 是专门用来加浏览器前缀的,可是它本身也就只能加个前缀而已,由于它本身不知道哪一个该加,哪一个不应加。因此咱们须要 autoprefixer 来告诉它,哪一个加,哪一个不加。
在根目录新增postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
复制代码
在package.json
中补充下列字段,来肯定咱们要支持到哪一步
"browserslist": [
"defaults",
"not ie < 11",
"last 2 versions",
"> 1%"
]
复制代码
未雨绸缪,咱们在此安装另外两个会用到的loader
yarn add url-loader file-loader --dev
复制代码
在webpack.config.js
中补充rules规则
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 2048,
}
},
'file-loader',
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
},
复制代码
Webpack 在启动后会从配置的入口模块出发找出全部依赖的模块,Resolve 配置 Webpack 如何寻找模块所对应的文件。
建立 import 或 require 的别名,来确保模块引入变得更简单。例如,一些位于 src/ 文件夹下的经常使用模块:
resolve: {
alias: {
'@': path.resolve(__dirname, "src/")
}
}
复制代码
如此,引用本身封装的组件或函数就能够以@
做为起始,例如
import BaseButton from "./components/Button/BaseButton";
复制代码
这样,避免了无止尽的../../../
,并且万一某个组件切换了目录,组件里的外部引用也不须要从新调整,由于它们老是相对于src路径开始寻找。
请注意,此处只是容许
webpack
打包时识别,要开启路径提示,须要配置tsconfig.json
中的path
,文末有附配置代码
每次文件修改后,从新打包,致使 dist 目录下的文件愈来愈多怎么办?
快使用clean-webpack-plugin
,每次构建自动为你清理/dist/
目录,留你想留,清你想清,一键配置,呵护懒癌晚期的你
yarn add clean-webpack-plugin --dev
复制代码
webpack.config.js
+ const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
plugins: [
+ new CleanWebpackPlugin({
+ cleanOnceBeforeBuildPatterns:['**/*', '!store', '!store/**'] // 不删除store目录下的文件
+ }),
],
};
复制代码
注意:本文没有拆分不一样环境的配置文件,在本地调试时,请注释掉这个插件
更多配置移步clean-webpack-plugin
你可能须要一个HtmlWebpackPlugin
,不然,你可能会想,react组件渲染了挂在哪里呢?找不到的话它会本身造一个Html
模版么?
并非,我只是由于懒没有建立模版文件,
当没有这个插件的时候,每次webpack打包生成的[name].bundle.js
须要手动配置,如今,它解放了你的双手,你能够快乐的干点别的事了。
yarn add html-webpack-plugin --dev
复制代码
不论你以前有没有建立,HtmlWebpackPlugin
会默认在输出目录
生成 index.html
文件,全部的 bundle 会自动添加到 html 中。
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns:['**/*', '!store', '!store/**'] // 不删除store目录下的文件
}),
+ new HtmlWebpackPlugin({
+ title: 'Basic react app'
+ })
],
复制代码
固然,通常来讲,咱们有时须要在public
目录下新建一个index.html
的模版文件,里面定义了一些咱们定制的内容,但我仍是不想占用个人双手在里面引入打包生成的bundle.js
文件。
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html', //打包后的文件名
config: config.template
})
复制代码
更多功能移步html-webpack-plugin
说了这么多,终于到了碰见Hello world
的时候了。不然我担忧你会看不下去。
webpack-dev-server 提供了一个简单的 web 服务器,而且可以实时从新加载(live reloading)。让咱们运行如下命令:
yarn add webpack-dev-server --dev
复制代码
修改配置文件
+ devServer: {
+ port: '3000', //默认是8080
+ publicPath: "http://localhost:3000/dist/",
+ hotOnly: true,
+ contentBase: './dist'
+ },
复制代码
在package.json中补充脚本
"scripts": {
"watch": "webpack --watch",
"start": "webpack-dev-server --open",
"build": "webpack"
},
复制代码
在命令行先执行yarn build
,再执行yarn start
,页面自动打开 -> 碰见Hello World
虽然咱们使用babel来编译 ts|tsx
文件,可是,有时候咱们还会怀念ts的类型错误检查,好比
“不!我不会编译这玩意儿的!你的代码在42个不一样的文件中出现异常!”
如何去检查类型错误呢?添加一段 lint 脚原本唤起 TypeScript 编译器。例如,将 npm test 命令调整为先检查类型,而后再继续运行单元测试。
因为性能问题,TypeScript 官方决定全面采用 ESLint,甚至把仓库(Repository)做为测试平台,而 ESLint 的 TypeScript 解析器也成为独立项目,专一解决双方兼容性问题。
yarn add eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin --dev
复制代码
同时,咱们是一个react app 项目,因此,你懂的
yarn add eslint-plugin-react eslint-plugin-react-hooks --dev
复制代码
在根目录下新建.eslintrc.js
文件,填入以下内容
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
parserOptions: {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 11,
"sourceType": "module",
project: './tsconfig.json',
},
plugins: [
"react",
"react-hooks",
'@typescript-eslint',
],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
],
};
复制代码
总有些文件是不须要检查的,作人么,能够为难别人,但不能为难本身,因此,在根目录建立一个.eslintignore
文件
config/
scripts/
node_modules/
\.eslintrc.js // 干掉它本身。。。
webpack.config.js
复制代码
通过考虑,补充 airbnb
规则
yarn add eslint-config-airbnb-typescript eslint-plugin-jsx-a11y eslint-plugin-import --dev
复制代码
eslintrc.js文件替换为
extends: [
'airbnb-typescript',
'plugin:@typescript-eslint/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
],
复制代码
不要忘了在
vscode
中下载eslint
插件
虽然上述规则通过了检验,但总有些对于咱们本身来讲是多余或者缺失的,因此在.eslintrc.js
文件补充 rules字段,用于开启或关闭某些规则
"rules": {
// 禁止使用 var
'no-var': "error",
// 优先使用 interface 而不是 type
'@typescript-eslint/consistent-type-definitions': [
"error",
"interface"
],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"react/prop-types": "off",
}
复制代码
修改package.json
中script脚本
"scripts": {
"lint": "eslint --ext .ts --ext .tsx src/",
"watch": "webpack --watch",
"start": "webpack-dev-server --open",
"build": "webpack"
},
复制代码
执行yarn lint
,而后愉快的扇本身吧。。。。
我在
src/index.tsx
中留了三个错误,大概? 你能够试着改一下
受不了检查记得禁止一些规则
忽然发现我没写怎么生成tsconfig.json
,两个方法,
tsc --init
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": false,
"outDir": "./dist/",
"forceConsistentCasingInFileNames": true,
"module": "commonjs",
"moduleResolution": "node",
"resolveJsonModule": true,
// "isolatedModules": true,
// "noEmit": true,
"jsx": "react",
"experimentalDecorators": true,
"baseUrl": ".",
"paths": {
"@/*":["src/*"]
}
},
"include": [
"src","test",
]
}
复制代码
配置项不是本文重点,主要是为了下面的内容。
在typscript中是没法识别非代码资源的,因此若是你试图import
一个svg|png
之类的文件就会提示你cannot find module '.png'
。
custom.d.ts
declare module "*.svg" {
const content: any;
export default content;
}
declare module "*.png" {
const content: any;
export default content;
}
复制代码
在tsconfig.json中有一个include字段,里面的内容表示ts须要转义的内容,将custom.d.ts
文件放到include
字段包含的目录中,就能够解决类型不识别的问题。
最后,这里附上
airbnb
规则传送门【airbnb】typescript-eslint
规则传送门【typescript-eslint】本篇教程到此结束,这只是一篇简明的指导式教程,若是有什么不对的地方,欢迎在评论中指出,我会及时修改
后续会针对webpack、eslint语法规范专门整理一期,工做较忙,时间就随缘了~
若是你收获了新知识,请点个赞吧~
本文收纳于: 从零开始的大前端筑基之旅(深刻浅出,持续更新~)
推荐阅读:
三言两语带你理解「闭包」|附使用场景
很简单就能解释清的东西为何要多费口舌呢?朝花夕拾,从新介绍继承与原型链
有图有真相的讲解回流(reflow)与重绘(repaint),KFC与MC
每次这两个都会被同时说起,关系就好像KFC边上必定会有MC同样亲密的让人摸不到头脑。让人恍然大悟的词法做用域及做用域链讲解
看图说话才是王道viewport和1px | 工具人: 这是1px,设计师: 不,这不是
设计我不行,但吵架我在行啊可食用的「css布局干货」,纯Html示例,可调试 | 水平、垂直、多列
可观看,可调试,可带走,仅此一家,别无分店前端必须掌握的「CSS层叠上下文」讲解 | 纯手工示例,包教包会
妹子与猫,你要哪一个?
参考文档