Cree manualmente un proyecto React desde cero usando webpack

Desde que entré en contacto con el front-end, cada vez que creo un nuevo proyecto, casi uso create-react-appandamios por conveniencia. Cuando llegué al trabajo, descubrí que los jefes construyeron y configuraron todos los proyectos de la empresa, y no necesitaba preocuparme por cómo se construyó el proyecto y algunos detalles de configuración interna. Aunque he visto algunas herramientas de empaquetado populares (como webpack, vite) en el mercado ahora, pero siempre las olvido después de leerlas. Sin practicarlas yo mismo, no puedo entender su verdadero significado. Entonces, este artículo usa materiales en línea para construir manualmente un proyecto React.

1. Inicializar el proyecto

Primero cree una carpeta de proyecto, que se llama zero-react-app en este artículo, para almacenar archivos de proyecto, como se muestra a continuación:

imagen.png

Luego ingrese a la interfaz del terminal cmd y cambie a la ruta de la carpeta:

imagen.png

Luego ingrese el comando en cmd npm initpara inicializar un proyecto:

npm init

La interfaz después de ejecutar es la siguiente:

imagen.png

Es necesario introducir cierta información relacionada con el proyecto:

  • nombre del paquete: nombre del proyecto
  • versión: versión del proyecto
  • descripción: descripción del artículo
  • punto de entrada: archivo de entrada
  • comando de prueba: comando de prueba
  • repositorio git: dirección del almacén Git
  • palabras clave: palabras clave
  • licencia: información de la versión

Esta información se puede ingresar directamente para usar los valores predeterminados, o puede personalizar la configuración.

npm initDespués de que el comando se ejecute correctamente, se creará un archivo en la carpeta del proyecto package.json, que almacena la información básica especificada al crear el proyecto:

imagen.png

¿Qué es el archivo paquete.json?

package.json se encuentra en el directorio raíz del proyecto y es el archivo de configuración del proyecto, como configurar el inicio del proyecto, empaquetar comandos y declarar paquetes dependientes.
Para elementos de configuración específicos, consulte el documento de npm o la introducción en Github .

2. Instalar paquete web

Primero instale el paquete web

npm install webpack webpack-cli -D

Después de la instalación, la carpeta del proyecto es la siguiente, con la adición de la carpeta node_modules y el archivo package-lock.json.

imagen.png

node_modules文件夹中存放着所有安装的依赖包。

package.json 和 package-lock.json的区别

package.json:运行 npm init 时生成,主要作用是描述项目以及记录项目依赖的模块信息(模块名称、大版本信息等)

package-lock.json:运行 npm install 时生成,用于记录所有模块的详细信息,包括版本信息、模块来源以及依赖的小版本信息等。

之所以引入 package.json 文件,主要用途在于:

  • 描述依赖关系树的单一表示,以便保证团队成员、部署和持续集成安装完全相同的依赖关系。(即锁定所有依赖的版本号)
  • npm install 重新安装全部依赖时,可以通过 package-lock.json 文件指定的下载地址和相关依赖,相对加快下载速度。

有关package-lock.json文件中具体配置,可以见官方说明

那为什么要安装 webpack 呢?

按官方定义,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 >webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个依赖图(dependency graph),然后>将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。

安装好webpack后,需要在根目录下创建一个webpack.config.js文件,这是webpack的配置文件。该文件配置主要包含以下几部分:

  • 入口(entry):指示 webpack 应该使用哪个模块来作为构建其内部依赖图的开始。默认值是 ./src/index.js。具体配置可见官方文档
module.exports = {
  entry: './path/to/my/entry/file.js',
};
  • 输出(output):告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹中。
const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    // bundle生成位置
    path: path.resolve(__dirname, 'dist'),
    // bundle文件名
    filename: 'my-first-webpack.bundle.js',
  },
};
  • loader:webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效模块,以供应用程序使用,以及被添加到依赖图中。loader主要用于转换源代码,可以使你在import 或 "load(加载)" 模块时预处理文件。通常有两个属性:
    • test 属性,识别出哪些文件会被转换。
    • use 属性,定义出在进行转换时,应该使用哪个 loader

module.rules 允许你在 webpack 配置中指定多个 loader。
loader 支持链式调用。链中的每个 loader 会将转换应用在已处理过的资源上。一组链式的 loader 将按照相反的顺序执行。链中的第一个 loader 将其结果传递给下一个 loader,依此类推。最后,链中的最后一个 loader,返回 webpack 所期望的 JavaScript。

module.exports = {
  module: {
    rules: [
      {
        test: /.css$/,
        use: [
          // [style-loader](/loaders/style-loader)
          { loader: 'style-loader' },
          // [css-loader](/loaders/css-loader)
          {
            loader: 'css-loader',
            options: {
              modules: true
            }
          },
          // [sass-loader](/loaders/sass-loader)
          { loader: 'sass-loader' }
        ]
      }
    ]
  }
};
  • 插件(plugin):loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。 webpack 插件是一个具有 apply 方法的 JavaScript 对象。apply 方法会被 webpack compiler 调用,并且在 整个 编译生命周期都可以访问 compiler 对象。
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 访问内置的插件
const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    filename: 'my-first-webpack.bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /.(js|jsx)$/,
        use: 'babel-loader',
      },
    ],
  },
  plugins: [
    new webpack.ProgressPlugin(),
    new HtmlWebpackPlugin({ template: './src/index.html' }),
  ],
};
  • 模式(mode):主要有开发模式(development)和生产模式(production

三、创建项目目录结构

  • 在项目根目录下创建 src文件夹。src文件夹用于存放项目代码文件.
    • 在其中创建一个index.js文件作为项目的入口文件。
  • 在项目根目录下创建public文件夹。
    • public文件夹下创建一个index.html文件,作为生成HTML文件的模板。

初始项目目录结构如下图:

imagen.png

紧接着向 webpack.config.js 中写入一些基本的webpack配置:

const path = require('path');

module.exports = {
    mode: 'development',  // 开发模式
    entry: './src/index.js', // 入口文件
    output: {
        // 必须是绝对路径
        path: path.resolve(__dirname, 'dist'), //打包后文件的输出位置
        filename: 'main.js',  // 打包后的文件名
        clean: true  // 打包之前清理dist文件夹
    },
}

我们在入口文件 ./src/index.js 文件中写入一段 JS 代码,测试是否能够打包成功:

imagen.png

然后运行 npx webpack --config webpack.config.js进行打包,可以看到打包后输出到了./dist/main.js

imagen.png

注意:

npx webpack --config webpack.config.js 可以简写为 npx webpack,因为当存在webpack.config.js文件时webpack会默认选择该文件,--config参数表明可以传递任何名称的配置文件。

四、安装 HtmlWebpackPlugin 插件

该插件将自动生成一个 HTML5 文件, 在 body 中使用 script 标签引入你所有 webpack 生成的 bundle。

npm install -D html-webpack-plugin

安装好后,我们可以在webpack.config.js文件中进行如下配置。

const htmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    ...
    plugins: [
        new htmlWebpackPlugin({
            template: './public/index.html',  // 生成HTML文件的模板文件
            filename: 'index.html',  // 生成的HTML文件名
            inject: 'body'  // <script>标签插入的地方
        })
    ],
    ...
}

然后我们每次使用 webpack 进行打包时,都会自动在dist文件夹中自动生成一个 index.html文件。

五、加载样式文件

项目中存在各种各样的样式文件,我们可以通过loader来加载。通常我们需要安装以下loader

以加载less文件为例;

首先安装相关loader 以及 less:

npm install -D style-loader css-loader less-loader less

然后在webpack.config.js文件中添加如下配置:

module.exports = {
    ...
    module: {
        rules: [
            {
                test: /\.(css|less)$/,
                use: ['style-loader', 'css-loader', 'less-loader']
            }
        ]
    } 
    ...
}

当 webpack 打包 less 文件时,会依次调用'less-loader', 'css-loader', 'style-loader'对less文件进行解析。['style-loader', 'css-loader', 'less-loader']的书写顺序和调用顺序(从后往前)相反。

抽离和压缩CSS

MiniCssExtractPlugin:会将CSS提取到单独的文件中,为每个包含CSS的JS文件(打包后的)创建一个CSS文件,并且支持CSS和SourceMaps的按需加载

npm install -D mini-css-extract-plugin

webpack.config.js中添加如下配置:

const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
    ...
    plugins: [
        new MiniCssExtractPlugin({
            filename: './styles/[contenthash].css'
        })
    ],
    module: {
        rules: [
            {
                test: /\.(css|less)$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
            }
        ]
    } 
    ...
}

CssMinimizerWebpackPlugin:这个插件使用cssnano优化和压缩CSS

npm install -D css-minimizer-webpack-plugin
const CssMinimizerWebpackPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
    ...
    mode: 'production',
    
   optimization: {
       minimizer: new CssMinimizerWebpackPlugin()
   }
    ...
}

六、静态资源打包

资源模块(asset module)是一种模块类型,它允许使用资源文件(字体,图标等)而无需配置额外 loader。

在 webpack 5 之前,通常使用:

资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:

  • asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。
  • asset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现。
  • asset/source 导出资源的源代码。之前通过使用 raw-loader 实现。
  • asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现。

例如打包 .png 格式的图片:

module.exports = {
    ...
    module: {
        rules: [
            {
                test: /\.png$/,
                type: 'asset/resource',
                generator: {
                    filename: 'images/[contenthash][ext]'
                }
            },
        ]
    } 
    ...
}

此外 webpack 也可以打包 .csv .xml 格式的文件,不过需要借助以下 loader:

  • csv-loader:将 csv 文件内容转换成数组
  • xml-loder:将 xml 文件内容转换成对象

这类静态资源如何打包,可根据官方文档以及具体项目需求进行配置。

七、支持 ES6 语法(babel-loader)

对于某些浏览器而言,并不支持 ES6 语法,所以需要使用babel-loader将代码转换成 ES5 语法。假设我们在index.js文件写入ES6的箭头函数:

image.png

然后我们看webpack打包后的文件:

image.png

可以看到,webpack 并未对其做任何转换。然后我们安装 babel-loader

npm install -D babel-loader @babel/core @babel/preset-env
  • babel-loader :webpack中用babel解析ES6的桥梁
  • @babel/core:babel的核心模块
  • @babel/preset-env:babel预设,一组babel插件的集合 然后在webpack.config.js文件中添加如下配置:
module.exports = {
    ...
    module: {
        rules: [
            {
                test: /\.m?js$/,
                exclude: /(node_modules)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
           }
        ]
    } 
    ...
}

然后再进行打包,可以看到箭头函数转换成了ES中的函数声明:

image.png

此外还需要安装regeneratorRuntime插件,这是webpack打包生成的全局辅助函数,由babel生成,用于兼容async/await语法。所以需要安装和配置插件:

// 该包中含有 regeneratorRuntime
npm install --save @babel/runtime

// 该插件会在需要regeneratorRuntime的地方自动require导入
npm install --save-dev @babel/plugin-transform-runtime

然后将配置文件修改如下:

module.exports = {
    ...
    module: {
        rules: [
            {
                test: /\.m?js$/,
                exclude: /(node_modules)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                        plugins: [
                            ["@babel/plugin-transform-runtime"]
                        ]
                    }
                }
           }
        ]
    } 
    ...
}

至此,babel相关配置已经完成。当然,实际项目中会根据实际要求进行更复杂的配置,可参考Babel官网

八、集成React

本文目的在于搭建一个 React 项目,上述已经完成了基本配置,紧接着我们将引入React。首先安装React:

npm install -D react react-dom

此外,我们仍然需要安装@babel/preset-react用于将 jsx 转换成 ES5.

npm install -D @babel/preset-react

然后在 webpack.config.js中添加如下配置:

{
    test: /\.(js|jsx)$/,
    exclude: /(node_modules)/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: [
            '@babel/preset-env',
            '@babel/preset-react'
        ],
        plugins: [
            // 主要改变在此处
            ["@babel/plugin-transform-runtime"]
        ]
      }
    }
}

然后我们在index.js中写入如下代码:

image.png

HTML 模板文件也需要进行如下修改:

image.png

然后执行打包命令,打包后的文件在浏览器中显示如下:

image.png

至此,一个简单的React项目就搭建完成了。

九、模块热更新

在实际开发过程中,如果每次修改后都执行一次npx webpack 打包命令,操作过于繁琐。对此,我们引入webpack-dev-server,提供一个本地的web服务,同时具有live reloading(实时重新加载)功能。

npm install -D webpack-dev-server

然后在 webpack.config.js中添加如下配置:

module.exports = {
    ...
    devServer: {
        hot: true,
        static: './dist'
    },
    ...
}

然后在 package.json 文件的script中添加启动命令:
"start": "webpack-dev-server --open-app-name chrome"

然后我们就可以在命令行中执行npm start 启动服务了。

十、引入 TypeScript

TypeScript se usa actualmente en la mayoría de los proyectos de desarrollo de front-end. TypeScript  es un superconjunto de JavaScript, que agrega un sistema de tipos y se puede compilar en código JavaScript ordinario. Si desea usar TypeScript para codificar en su proyecto, primero debemos instalar el compilador y cargador de TypeScript:

npm install -D typescript ts-loader

Luego agregue un archivo en el directorio raíz tsconfig.jsone ingrese la configuración básica:

{
  "compilerOptions": {
    "outDir": "./dist/",
    "noImplicitAny": true,
    "module": "es6",
    "target": "es5",
    "jsx": "react",
    "allowJs": true,
    "moduleResolution": "node"
  }
}

Para una configuración más detallada de TypeScript, puede consultar  la documentación oficial de TypeScript  para obtener más información sobre  tsconfig.json las opciones de configuración.

Hasta ahora, se ha creado un proyecto React simple. Por supuesto, hay configuraciones más complejas en desarrollo real. Puede consultar la documentación oficial del paquete web para la configuración.

Este artículo es un registro del proceso de aprendizaje para construir manualmente un proyecto React. Hay errores o lugares irrazonables en él. Bienvenido a corregirme.

referencia:

Cree proyectos de reacción manualmente sin andamios (webpack5 + Antd4 + React18)

Supongo que te gusta

Origin juejin.im/post/7255955134131404860
Recomendado
Clasificación