阅读 123

从0搭建React + webpack项目

全文介绍

本文主要介绍从0搭建一个React+webpack项目的过程,从而深刻了解webpack的基础用法。

1. 通过npm scripts执行webpack命令

上篇文章中我们通过 ./node_modules/.bin/webpack 执行打包任务,这样很不方便,现在介绍一种通过npm scripts执行构建的方式

修改package.json文件,在“scripts”对象中新增:"build": "webpack"

 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
},
复制代码

然后执行npm run build 即可执行webpack打包任务。 这种方式的原理是通过shell脚本在node_modules/.bin目录下创建一个软链接。

2.开始配置吧

2.1 使用babel-loader解析React和es新特性

首先在根目录下创建一个webpack的默认配置文件wenpack.config.js。然后安装react项目所需的react依赖。安装完成之后我们编写一个react组件。

/src/index.js

import React from 'react';
import ReactDOM from 'react-dom';

const MyComp = () => {
    return <div>React & Webpack</div>
}

ReactDOM.render(
    <MyComp />, 
    document.getElementById('app')    
)
复制代码

执行打包命令,不出意外,报错了。报错信息:

image.png 这是因为webpack开箱即用只支持JS和JOSN两种文件类型,我们需要通过loaders去支持其他文件类型并且把它们转化为有效模块。laoders的本事是一个函数,接受源文件作为参数,返回转换的结果。考虑到我们的项目,我们需要安装如下依赖:

  1. babel-loader 转换ES6,ES7等JS新特性语法。
  2. @babel/core和@babel/preset-env babel-loader的依赖
  3. @babel/preset-react react语法的解析配置

新增babel的配置文件.babelrc

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ]
}
复制代码

在webpack.config.js的配置中增加对js文件的babel-loader的使用:

const path = require('path')
module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'main.js',
        path: path.join(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                use: 'babel-loader'
            }
        ]
    }
}
复制代码

这样,再执行打包命令,就执行成功了。在打包后输出的dist文件夹中增加html文件,去加载打包出来的js文件看看效果:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>React & Webpack</title>
</head>

<body>
    <div id="app"></div>
    <script src="./main.js"></script>
</body>

</html>
复制代码

image.png

完美解析打包运行~

2.2 解析css和less

往往项目中还需要使用样式文件去修改我们的页面样式,webpack开箱即用也是不支持的,同理我们也需要使用laoder去解析样式文件。

  • 解析css:

安装依赖:

  1. style-loader 将css-loader生成的内容,以style挂载到⻚面的heade部分
  2. css-loader 分析css模块之间的关系,并合成一个css

在webpack.config.js中增加配置

const path = require('path')
module.exports = {
    ...
    module: {
        rules: [
            {
                test: /\.js$/,
                use: 'babel-loader'
            },
        +   {
        +       test: /\.css$/,
        +       use: ['style-loader', 'css-loader']
        +   }
        ]
    }
}
复制代码

laoder是按照从右至左的顺序加载的,所以css-loader要写在style-loader后面 给元素增加样式,并引入css文件

// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

const MyComp = () => {
    return <div className="red">React & Webpack</div>
}

ReactDOM.render(
    <MyComp />, 
    document.getElementById('app')    
)


//index.css
.red {
    color: red;
}
复制代码

打包完成后刷新浏览器,可以看到样式赋予成功,字体颜色修改为红色。

  • 解析less

只需要在使用一个less-loader 安装less-loader依赖和less依赖(less-loader依赖于less),并在解析less文件时调用该loader即可。

const path = require('path')
module.exports = {
    ...
    module: {
        rules: [
            ...
        +   {
        +       test: /\.css$/,
        +       use: ['style-loader', 'css-loader']
        +   },
        +   {
        +       test: /\.css$/,
        +       use: ['style-loader', 'css-loader', 'less-laoder']
        +   }
        ]
    }
}
复制代码

2.3 解析文本图片

安装依赖:

  1. file-loader 解析图片、文本资源

在webpack.config.js中增加配置

const path = require('path')
module.exports = {
    ...
    module: {
        rules: [
            ...
        +   {
        +       test: /\.(png|jpg|jpeg|gif)$/,
        +       use: 'file-loader'
        +   }
        ]
    }
}
复制代码

上述2.2与2.3中最终运行效果:

image.png

3. webpack文件监听

在上面几个步骤中,我们每次修改项目代码都需要手动执行打包更新,这不仅繁琐而且耗时。webpack作为目前最流行的模块打包器之一,自然也考虑到了这一痛点。webpack支持文件监听模式,当文件改变时,自动重新执行打包命令。启用 Watch 模式。这意味着在初始构建之后,webpack 将继续监听任何已解析文件的更改。

3.1 配置方式

webpack开启文件监听有两种方式:

  • webpack支持在CLI中传递--watch参数。
// package.json
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --watch"
},
复制代码
  • 配置webpack.config.js中设置watch为true

3.2 原理分析

webpack文件监听的原理就是轮询判断文件的 最后编辑时间 是否发生改变,某个文件发生改变后,并不会立即告诉监听者,而是先缓存起来,等待aggregateTimeout。webpack会将这段时间内进行的任何其他更改都聚合到一次重新构建里。

module.export={
    // 默认是false,不开启文件监听
    watch: true,
    watchOptions: {
        // 不监听的文件或文件夹
        ignored: /node_modules/,
        // 监听到变化后,等待多长时间再去执行,单位ms
        aggregateTimeout: 300,
        // 轮询频次,默认每秒询问1000次
        poll: 1000
    }
}
复制代码

4. webpack热更新

上述操作仍然需要通过手动刷新浏览器来同步代码修改内容,那有没有办法不刷新浏览器就达到目的呢?显然是有的。在webpack中有两种方式可以实现热更新:方式一借助webpack-dev-server(WDS)来实现热更新,WDS与打包不同,它不输出文件,而是放到内存中,因此构建速度更快。WDS一般还需要搭配HotModuleReplacementPlugin插件一起使用。方式二使用webpack-dev-middleware(WDM)来实现热更新。

4.1 WDS的使用

安装依赖webpack-dev-server(如果你和我一样安装是webpack5+,并且webpack-cli版本是4+,那么需要手动将webpack-cli版本降级为3,否则报错,方式可参考另一篇文章Cannot find module 'webpack-cli/bin/config-yargs'在package.json的scripts中增加dev命令

// package.json
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --watch"// --open 会自动打开默认浏览器
    "dev": "webpack-dev-server --open"
},
复制代码

在webpack.config.js中修改mode为development,并增加devServer。除此之外还需要使用webpack的HotModuleReplacementPlugin内置插件,来对webpack进行热更新增强。

const path = require('path')
const webpack = require('webpack')

module.exports = {
    ...
    mode: 'development',
    devServer: {
        port: 9000,
        contentBase: path.resolve(__dirname, './dist'),
        hot: true
    },
    module: {
        rules: [
            ...
        ]
    }
}
复制代码

然后执行 npm run dev,更改代码,查看浏览器,达到热更新效果。

4.2 WDM的使用

WDM需要借助node来实现,webpack输出的文件传输给服务器,一般适用于更加灵活地定制场景。

const express = require(’express')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const app = express()
const config = require('./webpack.config.js)
const compiler = webpack(config)

app.use(webpackDevMiddleware(compiler), {
    publicPath: config.output.publicPath
})

app.listen(8080, () => {
    console.log('app listening on port 8080')
})
复制代码
文章分类
前端
文章标签