[React项目总结一] 基于 webpack 搭建前端工程基础篇

目录

  1. 技术选型

  2. webpack 基础

    • 安装 webpack

    • webpack 简介

    • 使用webpack-dev-server启动服务器

  3. 配置 React,ES6 & Babel 6

  4. 使用 ESlint 进行代码检查

  5. 样式处理

  6. 图片处理

  7. 区分开发及生产环境

  8. 构建流程图

  9. 文件说明

  10. 参考

完整实例代码

git-repo
github issues

1. 技术选型

最近在一个项目初步尝试使用了reactJS,开发周期两周,选用的技术栈大致如下:

JavaScript:

  • Language: ES6

  • Framework: React,Redux

CSS:

  • Language: SCSS

  • Framework: ant-design

Build Tool:

  • Webpack

Dependency manage

  • npm

Git workflow:

  • Gitlab flow

API:

  • JSON

2. webpack 基础

2.1安装 webpack

作为全局变量安装

$ npm install -g webpack
 $ webpack -v => webpack 1.13.0

作为项目依赖安装

$ npm install webpack --save-dev

2.2 webpack 简介

webpack 的配置项主要包括以下几点:

  • entry: 入口,定义要打包的文件

  • output: 出口,定义打包输出的文件;包括路径,文件名,还可能有运行时的访问路径(publicPath)参数

  • module: webpack将所有的资源都看做是模块,而模块就需要加载器;主要定义一些loaders,定义哪些后缀名的文件应该用哪些loader

    • test: 检测哪些文件需要此loader,是一个正则表达式

    • exclude: 忽略哪些文件

  • resolve: 定义能够被打包的文件,文件后缀名

  • plugins: 定义一些额外的插件

示例用到的 Loaders
  • 处理样式:sass-loader、style-loader、css-loader,将 sass 转成 css

  • 图片处理,url-loader、file-loader、image-webpack-loader, 将图片转换成base64 或者 进行压缩

  • js处理: babel-loader,babel-preset-es2015,babel-preset-react,将es6或更高级的代码转成es5的代码

示例用到的 Plugins
  • 代码热替换:HotModuleReplacementPlugin

  • 生成html文件:HtmlWebpackPlugin

  • 报错但不退出webpack进程:NoErrorsPlugin

  • 代码压缩:UglifyJsPlugin

  • 自动打开浏览器: OpenBrowserPlugin

  • 设置环境变量: DefinePlugin

2.3 使用 webpack-dev-server 启动服务器

2.3.1 刷新功能

webpack提供的一个静态资源服务器,这个家伙可不太好配置,看官方文档给看懵了,试验了好几次才配成功,后面我们会根据 NODE_ENV 环境变量分别配置 dev mode server 和 prod mode serve;先来看看其功能:

  • 支持两种模式的自动刷新(Automatic Refresh)

    • iframe模式

    • inline模式

  • 支持热更新(Hot Module Replacement)

    注: 自动刷新和热更新是两个概念

2.3.2 这里主要介绍自动刷新 inline 模式的配置,inline模式又分为两种配置:
  • 命令行模式: 命令行模式只需要加上 --line选项即可

    $ webpack-dev-server --line
  • Node.js API: 使用node.js api需要手动添加配置

var config = {
   entry: [
     'webpack/hot/dev-server','webpack-dev-server/client?http://localhost:8080',path.resolve(__dirname,'app/index.js')
   ],}
2.3.3 配置 Hot Module Replacement

这是webpack最牛逼的特性之一,即模块热替换,在前端代码变动的时候无需整个刷新页面,只把变化的部分替换掉。使用HMR功能也有两种配置方式:

  • 命令行方式: 命令行模式只需要加上 --line --hot 选项。 --hot 会自动把 webpack/hot/dev-server 加入到了webpack配置文件中的入口点。如果执行正确,可以在浏览器的控制台看到以下信息。

    [HMR] Waiting for update signal from WDS...
    [WDS] Hot Module Replacement enabled.
  • Node.js API: 手动配置需要做三件事情:

    • webpack/hot/dev-server 加入到webpack配置文件的entry项

    • new webpack.HotModuleReplacementPlugin() 加入到webpack配置文件的plugins项

    • hot:true 加入到webpack-dev-server的配置项里面

2.3.4 完整配置,主要分为三部分:
  • webpack.config.js: webpack常规配置,配置入口文件,输出文件,loaders等等

  • server.js: 将server部分分离到一个单独到的文件配置

  • package.json: 自定义启动命令

<!-- webpack.config.js -->
 var webpack = require('webpack');
 var path = require('path');
 var config = {
   entry: [
     path.resolve(__dirname,'app/index.js')       // 定义入口文件
   ],output: {                                       // 定义出口目录
     path: path.resolve(__dirname,'build'),filename: 'bundle.js',publicPath: '/'
   },resolve: {                                      // resolve 指定可以被 import 的文件后缀
     extensions: ['','.js','.jsx']
   },module: {
   },plugins: [
     new webpack.HotModuleReplacementPlugin()
   ]
 }

 module.exports = config;
<!-- server.js -->
var webpack = require('webpack');
var webpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config.js');

var compiler = webpack(config);
var server = new webpackDevServer(compiler,{
  historyApiFallback: true,hot: true,inline: true,progress: true,contentBase: './app',stats: { colors: true }
});

config.entry.unshift("webpack-dev-server/client?http://localhost:8080/","webpack/hot/dev-server");

server.listen(8080,"localhost",function(err) {
  if(err) {
    console.log(err);
  }
  console.log('Listening at localhost:8080...');
});
<!-- package.json -->
"scripts": {
  "start": "node server.js"
}

现在你可以通过运行 npm start 启动服务器来。

3. 配置 React,ES6 & Babel 6

ES6 和 JSX 转换

在最新的babel 6.x 版本中,在指定哪些代码转换器将被启用时,需要配置 presets 。最简单配置的方法就是项目根目录下建一个 .babelrc 文件:

// .babelrc
{
  "presets": [
    "es2015","react"
  ]
 }

配置好以上代码,你就可以开始用 es2015,jsx 了,相关的依赖包

* babel-loader: 转换JSX
  * babel-core: 即babel的包
  * babel-preset-es2015: es2015的babel预设

4. 使用 ESlint 进行代码检查

特点:

  • 默认规则包含所有 JSLint、JSHint 中存在的规则,易迁移

  • 规则可配置性高:可设置「警告」、「错误」两个 error 等级,或者直接禁用;

  • ESLint 支持 JSX,不过目前为 alpha 版本,正式版发布之前可以先使用 eslint-plugin-react 替代

配置:

可以通过以下三种方式配置 ESLint:

  • 使用 .eslintrc 文件(支持 JSON 和 YAML 两种语法)

  • package.json 中添加 eslintConfig 配置块

  • 直接在代码文件中定义

下面主要演示通过 .eslintrc 配置的步骤:

4.1 在项目根目录下面新建 .eslintrc 文件
$ touch .eslintrc
4.2 Specifying Parser Options
{
  "parserOptions": {
    "ecmaVersion": 6,// 指定ECMAScript 版本
    "sourceType": "module",// 设置为 "script" (默认) 或 "module"(如果你的代码是 ECMAScript 模块)
    "ecmaFeatures": { 
        "jsx": true // 启用 JSX
    }
  }
}
4.3 Specifying Environments
{
  "env": {
    "browser": true,"node": true,"es6": true,"mocha": true
  }
}
4.4 Configuring Plugins
"plugins": [
  "plugin1","eslint-plugin-plugin2"
]
4.5 Configuring Rules
{
  "rules": {
      "eqeqeq": "off","curly": "error","quotes": ["error","double"]
  }
}
4.6 Extending Configuration Files
  • extends 属性值可以是:

    • 在配置中指定的一个字符串

    • 字符串数组:每个配置继承它前面的配置

*rules 属性可以做下面的任何事情以扩展(或覆盖)规则:
参数:0 关闭,1 警告,2 错误

  • 启用额外的规则

  • 覆盖基础配置中的规则的默认选项

  • 禁用基础配置中的规则

4.7 以下是eslint配置文件常见的格式
{
  "parserOptions": { //EsLint通过parserOptions,允许指定校验的ecma的版本,及ecma的一些特性
    "ecmaVersion": 6,//指定ECMAScript支持的版本,6为ES6
    "sourceType": "module",//指定来源的类型,有两种”script”或”module”
    "ecmaFeatures": { // ecmaFeatures指定你想使用哪些额外的语言特性
        "jsx": true //启动JSX
    }
  },"parser": "babel-eslint",// EsLint默认使用esprima做脚本解析,也可以切换成babel-eslint解析
  "env": { // Environment可以预设好的其他环境的全局变量,如brower、node环境变量、es6环境变量、mocha环境变量等
    "browser": true,"mocha": true
  },"plugins": [ // EsLint允许使用第三方插件
    "react"
  ],extends: [ // Extends是EsLint默认推荐的验证你可以使用配置选择哪些校验是你所需要的
    "eslint:recommended"
  ],rules: [ // 自定义规则
  ],"globals": { // 即插件在执行过程中用到的其它全局变量
  }
}
4.8 Ignoring Files and Directories

通过在项目根目录创建一个 .eslintignore 文件告诉 ESLint 去忽略特定的文件和目录。

4.9 在Sublime中安装插件:
SublimeLinter
SublimeLinter-contrib-eslint
4.10 相关插件
  • babel-eslint: ESLint 是前端JS代码检测利器。而 babel-eslint 则允许你检测所有的 Babel 代码

  • eslint: JavaScript 语法检测利器:分析出你代码潜在的错误和非标准用法

  • eslint-plugin-react: ESLint 中关于 React 语法检测的插件

4.11工作流集成

  • 编辑器

  • 构建工具

4.12 更多参考

4.13 运行 "eslint app

5. 样式处理

主要使用sass预处理器编写样式,需要先通过sass-loader处理成css,然后再通过css-loader加载成css模块,最后由style-loader加载器对其做最后的处理,从而运行时可以通过style标签将其应用到最终的浏览器环境。

$ npm install css-loader style-loader sass-loader node-sass --save-dev

安装好依赖后,通过以下简单的配置就可以使用sass;这里需要注意的一点是需要开启 sourceMap 功能,便于调试。

devtool: "source-map",module: {
 loaders: [
   {
     test: /(\.css|\.scss)$/,loaders: ["style","css?sourceMap","sass?sourceMap"]
   }
 ]
}

6. 图片处理

图片处理常见的loader有以下三种:

  • file-loader: 默认情况下会根据图片生成对应的 MD5 hash 的文件格式

  • url-loader: url-loader类似于file-loader,但是url-loader可以根据自定义文件大小或者转化为 base64 格式的 dataUrl,或者单独作为文件,也可以自定义对应的 hash 文件名

  • image-webpack-loader: 提供压缩图片的功能

// url-loader 配置
module: {
  loaders: [
    {
      test: /\.(jpe?g|png|gif|svg)$/i,loaders: [
        'url?limit=10000&name=img/[hash:8].[name].[ext]',// 图片小于8k就转化为 base64,或者单独作为文件
        'image-webpack' // 图片压缩
      ]
    }
  ]
}
// file-loader 配置
module: {
  loaders: [
    test: /\.(jpe?g|png|gif|svg)$/i,loaders: [
      'file?hash=sha512&digest=hex&name=[hash].[ext]',// 生成 md5 hash 格式的文件名
      'image-webpack' // 图片压缩
    ]
  ]
}

对于小质量的图片资源,可以由 url-loader 实现将其进行统一打包,代码中 url-loader?limit=8192 的含义就是对于所有小于 8kb 的图片资源转换成base64 格式。这在一定程度上可以替代CSS Sprites方案,用于减少对于小图片资源的HTTP请求数量。

7. 配置生产环境

7.1 前端开发环境通常分为两种:
  • 开发环境: 需要日志输出,sourcemap ,错误报告等等

  • 生产环境:需要做代码压缩,对文件名进行 hash 处理等等

为了区分我们可以创建两个文件分别进行不同环境下的配置:

  • webpack.config.dev.js // 开发环境

  • webpack.config.prod.js // 生产环境

7.2 区分环境

webpack 提供了 DefinePlugin 设置环境变量,后面会根据设置的不同环境变量决定是否打包压缩,还是启动dev server 或者是 prod server

plugins: [
    ...
    new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify('production') // or development
    }),]

判断当前环境是否是生产环境

var isProduction = function () {
  return process.env.NODE_ENV === 'production';
};

7.3 代码压缩

webPack 提供了内建插件,直接配置以下代码即可压缩代码

new webpack.optimize.UglifyJsPlugin({
  compress: {
    warnings: false
  }
})
7.4 添加 Hash 缓存
  • 对于没有修改的文件,从缓存中获取文件

  • 对于已经修改的文件,不要从缓存中获取

output: {
    ...
    filename: '[chunkhash:8].bundle.js' // chunkhash 默认是16位,可自定义配置
    ...
  },
7.5 自动生成页面

文件名带上 hash 值后,这个值在每次编译的时候都会发生变化,都需要在 html 文件里手动修改引用的文件名,这种重复工作很琐碎且容易出错,这里我们可以使用 html-webpack-plugin 来帮我们自动处理这件事情, 用来简化创建服务于 webpack bundle 的 HTML 文件,流程如下:

// 在 app 目录下建一个 index.tpl.html 作为钩子
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
// 在 webpack.config.dev.js 和 webpack.config.prod.js 添加配置代码,即可生成相对应的 index.html
plugins: [
  new HtmlWebpackPlugin({
    template: 'app/index.tpl.html',inject: 'body',filename: 'index.html'
  })
]

8 构建流程图

最终实现的构建流程如下图所示:

Configuration tasks

  • npm start: 启动开发模式下的server

  • npm run start:prod: 启动生产模式的server

  • npm run build: 打包生产模式的代码

  • npm run lint: eslint 代码检查

  • npm run lint:watch: eslint 监视

  • npm run remove:build: 删除dist目录

  • npm run clean:build : 清除dist目录

9. 文件说明

  • .babelrc: 配置 es2015,react 解析器

  • .eslintrc: 配置 eslint 代码检查

  • server.js: 配置本地 server (包含 dev server 和 prod server )

  • webpack.config.dev.js: 开发模式相关配置

  • webpack.config.prod.js: 生产模式相关配置

10. 参考

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom