最简单的搭建react项目,是通过脚手架命令create-react-app进行项目创建。

但是里面的webpack配置错综复杂,要修改不知从何下手。

如何让整个项目都在自己掌握之中?

今天给大家手写一个React项目配置。

1 新建项目

1. 找一个目录,新建项目文件夹

mkdir webpack-demo

2. 到项目文件夹根目录下生成package.json文件

cd webpack-demo
npm init -y

3. 安装webpack

npm install webpack webpack-cli --save-dev

4. 创建以下目录结构、文件和内容:

文件目录

  webpack-demo
  |- package.json
  |- /src
   |- index.js
   |- index.html

src/index.js

function component() {
  const element = document.createElement('div');

  // lodash(目前通过一个 script 引入)对于执行这一行是必需的
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');

  return element;
}

document.body.appendChild(component());

src/index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>起步</title>
    <script src="https://unpkg.com/lodash@4.17.20"></script>
  </head>
  <body>
    <script src="./src/index.js"></script>
  </body>
</html>

5. 修改package.json文件

我们还需要调整 package.json 文件,以便确保我们安装包是 private(私有的),并且移除 main 入口。这可以防止意外发布你的代码。

  //删除该行
  "main": "index.js",
  //添加该行
  "private": true,

package.json

 {
   "name": "webpack-demo",
   "version": "1.0.0",
   "description": "",
  -"main": "index.js",
  +"private": true,
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
   },
   "keywords": [],
   "author": "",
   "license": "MIT",
   "devDependencies": {
     "webpack": "^5.38.1",
     "webpack-cli": "^4.7.2",
   }
 }

6. 新建webpack.config.js配置

文件目录 新增webpack.config.js文件

  webpack-demo
  |- package.json
  |- webpack.config.js
  |- /src
   |- index.js
   |- index.html

webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

到此,你可以通过运行npx webpack来启动项目。

为了更符合工程化开发,我们接着添加一些必要的webpack配置

2 配置编译JS文件

前面我们已经配置过了,再单独列一下。

添加webpack配置如下:

//webpack 是用nodejs写的,是node语法

let path = require('path')//node提供的 相对路径 转 绝对路径 的插件

console.log(path.resolve(__dirname, "src"))
module.exports = {
  mode:"development",//模式,两种模式,产线模式"production"、开发模式"development"。产线模式会把编译文件进行压缩优化,代码变成一行。
  entry: "./src/aaa.js",//入口,相对路径
  output: {
    filename: "bundle.js",//打包后的文件名
    path: path.resolve(__dirname, "dist"),//打包后的路径(文件夹路径),必须是绝对路径,"__dirname"指当前路径
  }
}

本节具体参考:https://maomao.ink/index.php/IT/1008.html

3 配置编译Html文件

1. 安装html-webpack-plugin插件

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

2. webpack文件添加如下配置:

let HtmlWebpackPlugin = require("html-webpack-plugin")//html webpack 插件
module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: "./src/index.html",//模版文件(源文件)地址
      filename: "index.html"//打包后文件名
    })
  ]
}

本节具体参考:https://maomao.ink/index.php/IT/1017.html

4 搭建本地服务器

1. 安装webpack-dev-server

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

2. webpack文件添加如下配置:

module.exports = {
    devServer: {//开发服务器配置
        port: 3000,//端口号
        static: './dist',
        compress: true,//是否压缩
    },
}

3. pakage.json文件添加如下配置:

"scripts": {
    "dev":"webpack-dev-server"
  },

4. 运行npm run dev

npm run dev

运行成功后会自动在浏览器里打开项目路径“http://localhost:3000/

本节具体参考:https://maomao.ink/index.php/IT/1013.html

5 编译CSS

1. 安装css-loader,style-loader

npm install style-loader css-loader --save-dev

2. webpack文件添加如下配置:

module.exports = {
    module: {//模块
        rules: [//规则,多个loader
            {
                test: /\.css$/,//匹配到css结尾的文件,加载css-loader,
                //css-loader负责解析@import语法,将多个css文件合并成一个
                //style-loader负责把css文件插入到<head>标签中
                //loader的特点:功能单一
                //loader的用法:
                //use:"css-loader"字符串形式只能用一个loader
                //use:[]数组形式可以用多个loader
                //多个loader时,加载顺序是从后往前加载(从右向左执行)
                use: [{
                    loader: "style-loader",
                    options: {
                        //将当前loader添加到<head>标签内容的最上面
                        insert: function (element) {
                            var parent = document.querySelector('head');
                            var lastInsertedElement = window._lastElementInsertedByStyleLoader;
                            if (!lastInsertedElement) {
                                parent.insertBefore(element, parent.firstChild);
                            } else if (lastInsertedElement.nextSibling) {
                                parent.insertBefore(element, lastInsertedElement.nextSibling)
                            } else {
                                parent.appendChild(element)
                            }
                        }
                    }
                }, "css-loader"]
            },
        ]
    }
};

本节具体参考:https://maomao.ink/index.php/IT/1023.html

6 编译JS高级语法转es5

1. 安装必要插件

npm i babel-loader @babel/core @babel/runtime @babel/preset-env @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime -D

2.新增.babelrc文件(根目录下),配置参数:

{
    "presets": [
        "@babel/preset-env"
    ],
    "plugins": [
        "@babel/plugin-transform-runtime",
        "@babel/plugin-proposal-class-properties"
    ]
}

3. webpack文件添加如下配置:

module.exports = {
    module: {//模块
        rules: [//规则,多个loader
            {
                test: /\.js$/,
                use: {
                    //用 babel-loader 把es6转es5
                    loader: "babel-loader",
                }
            },
        ]
    }
};

4. 查看结果
运行:

npm run dev

本节具体参考:https://maomao.ink/index.php/IT/1035.html

以上配置可以基本满足开发需求。

如有更过优化需求,可以参考我的自研教程:https://maomao.ink/index.php/IT/868.html

最后,放送完整webpack配置文件内容如下:

const path = require('path');
let HtmlWebpackPlugin = require("html-webpack-plugin")//html webpack 插件

module.exports = {
    entry: './src/index.js',//入口,相对路径
    output: {
        filename: 'main.js',//打包后的文件名
        path: path.resolve(__dirname, 'dist'),//打包后的路径(文件夹路径),必须是绝对路径,"__dirname"指当前路径
    },
    mode: "development",//模式,两种模式,产线模式"production"、开发模式"development"。产线模式会把编译文件进行压缩优化,代码变成一行。
    devServer: {//开发服务器配置
        port: 3000,//端口号
        static: './dist',
        compress: true,//是否压缩
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: "./src/index.html",//模版文件(源文件)地址
            filename: "index.html"//打包后文件名
        })
    ],
    module: {//模块
        rules: [//规则,多个loader
            {
                test: /\.js$/,
                use: {
                    //用 babel-loader 把es6转es5
                    loader: "babel-loader",
                }
            },
            {
                test: /\.css$/,//匹配到css结尾的文件,加载css-loader,
                //css-loader负责解析@import语法,将多个css文件合并成一个
                //style-loader负责把css文件插入到<head>标签中
                //loader的特点:功能单一
                //loader的用法:
                //use:"css-loader"字符串形式只能用一个loader
                //use:[]数组形式可以用多个loader
                //多个loader时,加载顺序是从后往前加载(从右向左执行)
                use: [{
                    loader: "style-loader",
                    options: {
                        //将当前loader添加到<head>标签内容的最上面
                        insert: function (element) {
                            var parent = document.querySelector('head');
                            var lastInsertedElement = window._lastElementInsertedByStyleLoader;
                            if (!lastInsertedElement) {
                                parent.insertBefore(element, parent.firstChild);
                            } else if (lastInsertedElement.nextSibling) {
                                parent.insertBefore(element, lastInsertedElement.nextSibling)
                            } else {
                                parent.appendChild(element)
                            }
                        }
                    }
                }, "css-loader"]
            },
            {
                test: /\.less$/,//匹配到less结尾的文件
                use: [{
                    loader: "style-loader",
                    options: {
                        //将当前loader添加到<head>标签内容的最上面
                        insert: function (element) {
                            var parent = document.querySelector('head');
                            var lastInsertedElement = window._lastElementInsertedByStyleLoader;
                            if (!lastInsertedElement) {
                                parent.insertBefore(element, parent.firstChild);
                            } else if (lastInsertedElement.nextSibling) {
                                parent.insertBefore(element, lastInsertedElement.nextSibling)
                            } else {
                                parent.appendChild(element)
                            }
                        }
                    }
                }, "css-loader", "less-loader"]
            }
        ]
    }
};