基于webpack的React项目搭建(二)

前言

前面咱们已经搭建了基础环境,如今将开发环境更完善一些。css

  • devtool

在开发的过程,咱们会常常调试,so,为了方便咱们在chrome中调试源代码,须要更改webpack.config.js,而后启动webpack-dev-server。完成以后在chrome浏览器中打开debug,点击Sources选项,便可看见提示,继而输入你想查看的源文件名便可显示该文件源代码,若是你以为某处代码有问题,对应行号打上断点便可调试。html

......
module.exports = {
    devtool: 'cheap-module-eval-source-map',
    ......
 }

  • 热更新(HMR)

HMR应该是webpack使人很是兴奋的一个特色,它在代码修改后从新打包并发送到浏览器,浏览器将获取的新模块替换老模块,在不刷新浏览器的状况下实现对应用的更新。因为咱们使用的是webpack-dev-server,它提供了两种自动刷新方式供咱们选择,iframe和inline模式。这里咱们选择inline模式,更改dev-server.js。node

......
const server = new WebpackDevServer(compiler, { contentBase: path.resolve(__dirname, '../build'), // 默认会以根文件夹提供本地服务器,这里指定文件夹 inline: true, // 自动刷新 hot: true, // 开启热模块替换
......

 更改webpack.config.jsreact

......
const webpack = require('webpack');
module.exports = { devtool: 'cheap-module-eval-source-map', entry: [
     
'webpack-dev-server/client?http://localhost:9090', 'webpack/hot/only-dev-server', path.resolve(__dirname, '../src/index.js') ],
   ...... plugins: [
new webpack.HotModuleReplacementPlugin()
     ...... ]

 最后更改index.jswebpack

import React from 'react';
import { render } from 'react-dom';
import App from './App'

const renderDom = Component => {
    render(
        <Component />,
        document.getElementById('app')
    );
}
renderDom(App);

if (module.hot) {
    module.hot.accept('./App', () => {
        const App = require('./App').default;
        renderDom(App);
    })
} 

接下来执行npm run dev,查看浏览器,发现以下就实现了热更新。es6

而后修改App.js里render返回的html,保存后能够发现浏览器会自动刷新并看到你更改后的效果。也许这样就实现了React组件的热更新,Right ?咱们对App.js作以下更改看看会有什么变化。web

import React, { Component } from 'react';

export default class App extends Component {
    constructor(props) { super(props); this.state = {
            count: 1,
        }
    }

    add () {
        this.setState({ count: this.state.count + 1 });
    };
    render() {
        return (
            <div>
                <h1>{this.state.count}</h1>
                <button onClick={() => this.add()}>增长1</button>
            </div>
 ); }
}

而后在浏览器中点击按钮,页面中数值随之增长。而后,咱们修改一下App.js(在button标签下增长其余标签),保存后浏览器自动刷新。咱们查看一下浏览器,那么问题来了,刚刚点击增长后的数值不见了,又回到了初始值1。这时候发现组件的状态并无保存下来,没有达到真正意义上的React热更新。因此这里还须要引入一个插件,来帮咱们解决热更新组件状态保存问题。这也是react-hot-loader的由来。chrome

npm install react-hot-loader --save-dev
npm install babel-polyfill --save

 更改webpack.config.js。npm

......
module.exports = { devtool: 'cheap-module-eval-source-map', entry: [ 'babel-polyfill', 'react-hot-loader/patch', 'webpack-dev-server/client?http://localhost:8080', 'webpack/hot/only-dev-server',
......

 更改index.js。json

......
import { AppContainer } from 'react-hot-loader'; import 'babel-polyfill'
; import App from './App'; const renderDom = Component => { render( <AppContainer> <Component /> </AppContainer>, document.getElementById('app') ); };
......

 更改.babelrc。

{
  "presets": [
    [ "es2015",
      {
        "module": false
      }
    ],
    "react"
  ],
  "plugins": [
    "react-hot-loader/babel"]
}

修改完后,须要从新执行npm run dev。咱们重复上面的操做,能够发现,没有再出现上面的问题。固然上面的React函数绑定还有多种写法:

//方式一
<button onClick={() => this.add()}>增长1</button>

//方式二
<button onClick={this.add.bind(this)}>增长1</button>

//方式三,官方推荐使用
constructor(props) {
    super(props)
    this.add = this.add.bind(this);
}
<button onClick={this.add)}>增长1</button>
//方式四,推荐(因为处于草案阶段,因此是以插件的方式使用)
add = () => {
  ......
} <button onClick={this.add)}>增长1</button>

我更倾向于第四种,更简洁。这里咱们配置一下第四种方式。

npm install babel-preset-stage-1 --save  

 最后修改.babelrc便可。

......
"react", "stage-1"
......
  •  ESLint语法校验

  一个JavaScript语法检测工具,能够像IDE同样静态检测代码错误并提示。首先安装eslinteslint-loader

npm install eslint eslint-loader --save-dev

   修改webpack.config.js。

......
module: { rules: [ { enforce:
"pre", test: /\.(js|jsx)$/, loader: 'eslint-loader', exclude: /node_modules/ },
......

  项目根目录下新建.eslintrc.json。

{
  "rules": {

  }
}

  咱们先不建立规则,直接运行会报error Parsing error: The keyword 'import' is reserved,由于项目中使用了es6等新语法,而这些还不能被直接识别,因此还需安装babel-eslint进行转义。

npm install babel-eslint --save-dev

  修改.eslintrc.json文件。

{
  "parser": "babel-eslint",
  "rules": {

  }
}

  上述修改完后,就能够从新运行了。到这里,咱们能够开始自定义规则,你能够将本身的规则开源出来供你们一块儿使用。然而要从头至尾所有自定义规则并不切合实际,所幸已经有不少符合最佳实践的规则。这里咱们选择Airbnb,安装eslint-config-airbnb(推荐)。

npm install eslint-config-airbnb --save-dev

  eslint-config-airbnb须要下面3个插件的支持:

npm install eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react --save-dev

  修改.eslintrc.json,暂时加入如下规则。

{
  "parser": "babel-eslint",
  "extends": "airbnb",
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  },
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "plugins": [
    "react"
  ],
  "rules": {
    "react/jsx-no-bind": [
      "error",
      {
        "ignoreRefs": true,
        "allowArrowFunctions": true,
        "allowBind": true
      }
    ],
    "import/no-extraneous-dependencies": "off",
    "react/jsx-filename-extension": "off"
  }
}

  配置好后从新运行,发现红了一片(不少错)。别急,咱们一步一步修改。首先修改index.js,在文件头部加上/*eslint-disable*/,不对index.js进行校验。剩余的咱们就不一一更改了,可让IDE(Webstorm)为咱们修改。选择WebStorm的Preferences,搜索ESLint,将咱们建立的规则应用到项目中。

  而后在报错的文件中,点击红色感叹号,点击第一项,便可自动修改错误。

  •  其余经常使用加载器

  其余经常使用加载器还有不少,这里简单将css配置了一下,其他就不一一配置介绍了,请自行按需配置。最后webpack.config.js配置以下。

    css-loader: 解析css代码

    style-laoder: 将编译后css样式导入到html中

    less-loader: 加载和转移less文件

    raw-loader: 加载文件原始内容(utf-8格式)

    url-loader: 多用于加载图片

    file-loader: 打包文件

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  devtool: 'cheap-module-eval-source-map',
  entry: [
    'babel-polyfill',
    'react-hot-loader/patch',
    'webpack-dev-server/client?http://localhost:9090',
    'webpack/hot/only-dev-server',
    path.resolve(__dirname, '../src/index.js'),
  ], // 指定入口文件,程序从这里开始编译,__dirname当前目录, ../表示上一级目录, ./同级目录
  output: {
    path: path.resolve(__dirname, '../dist'), // 输出的路径
    filename: 'app/[name]_[hash:8].js', // 打包后文件
  },
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.(js|jsx)$/,
        loader: 'eslint-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.(js|jsx)$/,
        loader: 'babel-loader', // 加载器
        exclude: /node_modules/,
      },
      {
        test: /\.css$/,
        use: [{
            loader: 'style-loader'
        }, {
            loader: 'css-loader'
        }],
      },
      {
        test: /\.less$/,
        use: [{
          loader: 'style-loader',
        }, {
          loader: 'css-loader',
        }, {
          loader: 'less-loader',
          options: {
            sourceMap: true,
          },
        }],
      },
    ],
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/index.template.html'),
      inject: true,
    }),
  ],
}; 
相关文章
相关标签/搜索