基于webpack4.X从零搭建React脚手架的方法步骤

小编 2026-07-04 阅读:1155 评论:0
项目初始化 $ npm init 安装webpack 本次创建是基于webpack4 $ npm install --save-dev 新建webpack配置文件...

项目初始化

$ npm init

安装webpack

本次创建是基于webpack4

$ npm install --save-dev

新建webpack配置文件

在根目录创建build文件夹,添加一个js文件,命名为webpack.base.conf.js

// webpack.base.conf.js 文件
const path = require(\'path\');
const DIST_PATH = path.resolve(__dirname, \'../dist\');
module.exports = {
    entry: {
      app: \'./app/index.js\'
    },
    output: {
      filename: \"js/bundle.js\",
      path: DIST_PATH
    }
};

使用merge的方式来组织webpack基础配置和不同环境的配置

先安装webpack-merge:

$ npm install --save-dev webpack-merge

在build文件夹中再添加一个js文件,命名为 webpack.prod.conf.js

// webpack.prod.conf.js 文件
const merge = require(\'webpack-merge\');
const baseWebpackConfig = require(\'./webpack.base.conf\');
module.exports = merge(baseWebpackConfig, {
  mode: \'production\'
});

在根目录下创建app目录,然后创建index.js文件

var element =document.getElementById(\'root\');
element.innerHTML = \'hello, world!\';

在根目录创建一个public文件夹,然后新建一个index.html文件

// index.html
<!DOCTYPE html>
<html lang=\"en\">
 <head>
   <meta charset=\"UTF-8\">
   <title>从零开始搭建react工程</title>
 </head>
 <body>
    <div id=\"root\"></div>
    <script src=\"../dist/js/bundle.js\"></script>
 </body>
</html>

当前项目目录树

|- /app
  |- index.js
 |- /node_modules
 |- /public
  |- index.html
 |- /build
  |- webpack.base.conf.js
  |- webpack.prod.conf.js
 |- package.json
 |- package-lock.json

安装webpack-cli

webpack 4.0 版本之后的webpack,已经将webpack命令工具迁移到webpack-cli模块了,需要安装 webpack-cli

$ npm install --save-dev webpack-cli

package.json文件 scripts属性配置一个build命令

其值为:webpack --config build/webpack.prod.conf.js,以下是scripts的相关代码

// package.json
\"scripts\": {
  \"build\": \"webpack --config build/webpack.prod.conf.js\",
  \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"
},

安装React

$ npm install --save react react-dom

修改app目录下的index.js的代码

import React from \"react\";
import ReactDom from \"react-dom\";

ReactDom.render(
  <h1>hello, world!</h1>,
  document.getElementById(\"root\")
);

注意 import 属于ES6规范,因此需要转译ES2015+的语法,安装并配置 babel 以及相关依赖

$ npm install --save-dev babel-loader babel-core babel-preset-env babel-preset-react

根目录创建.babelrc文件,配置presets.

{
 \"presets\": [
  [
   \"env\",
   {
    \"targets\": {
     \"browsers\": [
      \"> 1%\",
      \"last 5 versions\",
      \"ie >= 8\"
     ]
    }
   }
  ],
  \"react\"
 ]
}

修改webpack.base.conf.js文件

// webpack.base.conf.js
const path = require(\'path\');
const APP_PATH = path.resolve(__dirname, \'../app\');
const DIST_PATH = path.resolve(__dirname, \'../dist\');
module.exports = {
  entry: {
    app: \'./app/index.js\'
  },  
  output: {
    filename: \'js/bundle.js\',
    path: DIST_PATH
  },
  module: {
    rules: [
      {
        test: /\\.js?$/,
        use: \"babel-loader\",
        include: APP_PATH
      }
    ]
  }
};

运行 npm run build

添加插件

public下的index.html本该自动添加到dist目录,并且引用资源自动加载到该文件,通过html-webpack-plugin实现这一步

$ npm install html-webpack-plugin --save-dev

webpack.prod.conf.js中配置plugins属性

const merge = require(\'webpack-merge\');
const baseWebpackConfig = require(\'./webpack.base.conf.js\');
const HtmlWebpackPlugin = require(\'html-webpack-plugin\');

module.exports = merge(baseWebpackConfig, {
  mode: \'production\',
  plugins: [
    new HtmlWebpackPlugin({
      template: \'public/index.html\',
      inject: \'body\',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      },
    })
  ]
});

删除 index.html 中手动引入的 script 标签

<!DOCTYPE html>
<html lang=\"en\">
<head>
  <meta charset=\"UTF-8\">
  <title>从零开始搭建react工程</title>
</head>
<body>
  <div id=\"root\"></div>
</body>
</html>

重新编译查看 npm run build 浏览器打开查看目录 dist 下的 index.html

以上步骤都成功的前提下继续走下一步

生成的文件名添加Hash值,目的是解决缓存问题

修改webpack.prod.conf.js,mode: \'production\', 增加以下代码

// webpack.prod.conf.js
output: {
  filename: \"js/[name].[chunkhash:16].js\",
},

生成前需要清理之前项目生成的文件,因为由于文件名的改变如果不删除会一直增加

安装插件 clean-webpack-plugin

$ npm install --save-dev clean-webpack-plugin

修改 webpack.prod.conf.js

// webpack.prod.conf.js
const merge = require(\'webpack-merge\');
const baseWebpackConfig = require(\'./webpack.base.conf.js\');
const HtmlWebpackPlugin = require(\'html-webpack-plugin\');
const CleanWebpackPlugin = require(\'clean-webpack-plugin\');

module.exports = merge(baseWebpackConfig, {
  mode: \'production\',
  output: {
    filename: \"js/[name].[chunkhash:16].js\",
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: \'public/index.html\',
      inject: \'body\',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      },
    }),
    new CleanWebpackPlugin([\'../dist\'], { allowExternal: true })
  ]
});

公共代码与业务代码分离

修改 webpack.base.conf.js 的 entry 入口属性,抽出框架代码

entry: {
   app: \'./app/index.js\',
   framework: [\'react\',\'react-dom\'],
},

修改webpack.prod.conf.js,增加以下代码,目的是分离框架代码和业务代码

虽然上面步骤抽出框架代码生成两个文件,但是app.js还是包含框架代码

optimization: {
    splitChunks: {
      chunks: \"all\",
      minChunks: 1,
      minSize: 0,
      cacheGroups: {
        framework: {
          test: \"framework\",
          name: \"framework\",
          enforce: true
        }
      }
    }
  }

cacheGroups对象,定义了需要被抽离的模块

其中test属性是比较关键的一个值,他可以是一个字符串,也可以是正则表达式,还可以是函数。如果定义的是字符串,会匹配入口模块名称,会从其他模块中把包含这个模块的抽离出来

name是抽离后生成的名字,和入口文件模块名称相同,这样抽离出来的新生成的framework模块会覆盖被抽离的framework模块

整合 webpack-dev-server

开发环境开启服务监听文件改动实时更新最新内容

$ npm install --save-dev webpack-dev-server

在build中添加webpack.dev.conf.js文件

const path = require(\'path\');
const merge = require(\'webpack-merge\');
const baseWebpackConfig = require(\'./webpack.base.conf.js\');
const HtmlWebpackPlugin = require(\'html-webpack-plugin\');
const webpack = require(\'webpack\');

module.exports = merge(baseWebpackConfig, {
  mode: \'development\',
  output: {
    filename: \"js/[name].[hash:16].js\",
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: \'public/index.html\',
      inject: \'body\',
      minify: {
        html5: true
      },
      hash: false
    }),
    new webpack.HotModuleReplacementPlugin()
  ],
  devServer: {
    port: \'8080\',
    contentBase: path.join(__dirname, \'../public\'),
    compress: true,
    historyApiFallback: true,
    hot: true,
    https: false,
    noInfo: true,
    open: true,
    proxy: {}
  }
});

在package.json scripts属性添加内容

\"dev\": \"webpack-dev-server --inline --progress --config build/webpack.dev.conf.js\",

npm run dev

自动打开浏览器打开入口页面实时更新

独立导出 css 文件

安装css相关依赖

sass less 预处理

$ npm install extract-text-webpack-plugin
$ npm install style-loader css-loader postcss-loader autoprefixer --save-dev
$ npm install less sass less-loader sass-loader stylus-loader node-sass --save-dev

webpack.base.conf.js 文件修改

// webpack.base.conf.js
{
  test: /\\.css$/,
  use: [
    {
     loader: \"style-loader\" //在html中插入<style>标签
     },
     {
       loader: \"css-loader\",//获取引用资源,如@import,url()
     },
     {
       loader: \"postcss-loader\",
       options: {
          plugins:[
            require(\'autoprefixer\')({
              browsers:[\'last 5 version\']
            })
         ]
       }
    }
   ]
},
{
  test:/\\.less$/,
  use: [
     { loader: \"style-loader\" },
     { loader: \"css-loader\" },
     {
      loader: \"postcss-loader\",//自动加前缀
      options: {
          plugins:[
             require(\'autoprefixer\')({
               browsers:[\'last 5 version\']
             })
         ]
      }
     },
     { loader: \"less-loader\" }
   ]
},
{
   test:/\\.scss$/,
   use:[
       { loader: \"style-loader\" },
       {
           loader: \"css-loader\",
       },
       { loader: \"sass-loader\" },
       {
        loader: \"postcss-loader\",
       options: {
          plugins:[
             require(\'autoprefixer\')({
              browsers:[\'last 5 version\']
             })
          ]
       }
     }
   ]
},

图片和路径处理

$ npm i file-loader url-loader --save-dev

webpack.base.conf.js 文件修改

// webpack.base.conf.js
{
  test: /\\.(png|jpg|gif|woff|svg|eot|woff2|tff)$/,
  use: \'url-loader?limit=8129\', 
  //注意后面那个limit的参数,当你图片大小小于这个限制的时候,会自动启用base64编码图片
  exclude: /node_modules/
}

build 时报错

Error: Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead
    at Chunk.get (F:\\react\\createApp\\node_modules\\webpack\\lib\\Chunk.js:824:9)

webpack4.0中使用“extract-text-webpack-plugin”报错

解决办法

$ npm install extract-text-webpack-plugin@next

背景图片路径问题

由于css文件分离出来的原因,会导致在css文件夹下找images文件夹下的图片

解决办法 publicPath属性改为 \'/\',以绝对路径的方式寻找资源

{
  test:/\\.(png|jpg|gif)$/,
  use:[{
    loader:\'url-loader\',
    options: {
       // outputPath:\'../\',//输出**文件夹
       publicPath: \'/\',
       name: \"images/[name].[ext]\",
       limit:500 //是把小于500B的文件打成Base64的格式,写入JS
     }
   }]
},

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

上一篇:React学习笔记 下一篇:CentOS 7 修改时区
热门文章
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
标签列表