• 从零开始,构建属于自己的React项目,不使用脚手架,自己写webpack配置来实现


    反正突然脑子一热,就想试一试

    第一步,先定义好文件目录结构

    config

    webpack.base.js
    webpack.dev.js
    webpack.pro.js

    dist(打包自己生成的)

    js
    css
    index.html

    src(主目录)

    actions
    apis
    assets
    components
    mocks
    pages
    reducers
    routes
    store
    index.jsx(入口文件)

    .babelrc(babel的相关配置)

    .gitignore(git提交时忽略的文件)

    .npmignore(npm发布包时忽略的文件)

    package.json(包配置文件)

    README.md(项目说明文件)

    第二步,开始写webpack相应的配置,我的配置是从官网上下载下来,然后进行部分的修改。

    // webpack.base.js
    const path = require('path');
    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    
    const resolve = (url) => {
      return path.resolve(__dirname, url);
    }
    
    module.exports = {
      // mode: "development", // "production" | "development" | "none"  // Chosen mode tells webpack to use its built-in optimizations accordingly.
      entry: resolve("../src/index"), // string | object | array  // 这里应用程序开始执行
      // webpack 开始打包
      output: {
        // webpack 如何输出结果的相关选项
        path: resolve("../dist/js"), // string
        // 所有输出文件的目标路径
        // 必须是绝对路径(使用 Node.js 的 path 模块)
        filename: "js/index.js", // string    // 「入口分块(entry chunk)」的文件名模板(出口分块?)使用HtmlWebpackPlugin时引入的js文件就是这个路径
        publicPath: "/", // string    // 输出解析文件的目录,url 相对于 HTML 页面
        library: "MyLibrary", // string,
        // 导出库(exported library)的名称
        libraryTarget: "umd", // 通用模块定义    // 导出库(exported library)的类型
        /* 高级输出配置(点击显示) */
      },
    
      module: {
        // 关于模块配置
        rules: [
          // 模块规则(配置 loader、解析器等选项)
          {
            test: /.js|jsx$/,
            exclude: /node_modules/,
            include: [
              resolve("../src")
            ],
            // 这里是匹配条件,每个选项都接收一个正则表达式或字符串
            // test 和 include 具有相同的作用,都是必须匹配选项
            // exclude 是必不匹配选项(优先于 test 和 include)
            // 最佳实践:
            // - 只在 test 和 文件名匹配 中使用正则表达式
            // - 在 include 和 exclude 中使用绝对路径数组
            // - 尽量避免 exclude,更倾向于使用 include
            // issuer: { test, include, exclude },
            // issuer 条件(导入源)
            // enforce: "pre",
            // enforce: "post",
            // 标识应用这些规则,即使规则覆盖(高级选项)
            loader: "babel-loader",
            // 应该应用的 loader,它相对上下文解析
            // 为了更清晰,`-loader` 后缀在 webpack 2 中不再是可选的
            // 查看 webpack 1 升级指南。
            options: {
              presets: ["@babel/preset-env", "@babel/preset-react"]
            },
            // loader 的可选项
          },
          {
            test: /.html$/,
            use: [
              // 应用多个 loader 和选项
              "htmllint-loader",
              {
                loader: "html-loader"
              }
            ]
          },
          {
            test: /.less$/,
            use: [
              {
                loader: MiniCssExtractPlugin.loader,
                options: {
                  // 这里可以指定一个 publicPath
                  // 默认使用 webpackOptions.output中的publicPath
                  publicPath: './css'
                },
              },
              // 'style-loader',
              'css-loader',
              'less-loader',
            ]
          },
          {
            test: /.css$/,
            exclude: /node_modules/,
            use: [
              {
                loader: MiniCssExtractPlugin.loader,
              },
              // 'style-loader',
              'css-loader'
            ]
          },
          {
            test: /.(png|jpg|gif)$/,
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 8192
                }
              }
            ]
          }
        ],
      },
      resolve: {
        // 解析模块请求的选项
        // (不适用于对 loader 解析)
        modules: [
          "node_modules",
          resolve("src")
        ],
        // 用于查找模块的目录
        extensions: [".js", ".json", ".jsx", ".css", ".less"],
        // 使用的扩展名
        alias: {
          // 模块别名列表
          // "module": "new-module",
          // 起别名:"module" -> "new-module" 和 "module/path/file" -> "new-module/path/file"
          // "only-module$": "new-module",
          // 起别名 "only-module" -> "new-module",但不匹配 "only-module/path/file" -> "new-module/path/file"
          // "module": path.resolve(__dirname, "app/third/module.js"),
          // 起别名 "module" -> "./app/third/module.js" 和 "module/file" 会导致错误
          // 模块别名相对于当前上下文导入
          "Actions": resolve("../src/actions"),
          "Apis": resolve("../src/apis"),
          "Assets": resolve("../src/assets"),
          "Components": resolve("../src/components"),
          "Mocks": resolve("../src/mocks"),
          "Pages": resolve("../src/pages"),
          "Reducers": resolve("../src/reducers"),
          "Routes": resolve("../src/routes"),
          "Store": resolve("../src/store"),
        },
        /* 可供选择的别名语法(点击展示) */
        /* 高级解析选项(点击展示) */
      },
      plugins: [
        new MiniCssExtractPlugin({
          // 类似 webpackOptions.output里面的配置 可以忽略
          filename: 'css/[name].css',
          chunkFilename: 'css/[id].css',
        }),
        new HtmlWebpackPlugin({
          filename: 'index.html',
          template: resolve('../src/assets/index.html')
        }),
        new CleanWebpackPlugin(), // 打包之前清空dist文件夹
      ],
    }
    
    // webpack.dev.js
    const DashboardPlugin = require('webpack-dashboard/plugin');
    
    const path = require('path');
    const webpack = require('webpack');
    
    const config = require('./webpack.base');
    
    const resolve = (url) => {
      return path.resolve(__dirname, url);
    }
    
    process.env.NODE_ENV = 'development';
    
    module.exports = {
      ...config,
      mode: 'development',
      devtool: "source-map", // enum  // 通过在浏览器调试工具(browser devtools)中添加元信息(meta info)增强调试
      // 牺牲了构建速度的 `source-map' 是最详细的。
      context: __dirname, // string(绝对路径!)
      // webpack 的主目录
      // entry 和 module.rules.loader 选项
      // 相对于此目录解析
    
      target: "web", // 枚举  // 包(bundle)应该运行的环境
      // 更改 块加载行为(chunk loading behavior) 和 可用模块(available module)
      stats: "errors-only",  // 精确控制要显示的 bundle 信息
      devServer: {
        proxy: { // proxy URLs to backend development server
          '/api': 'http://localhost:8888'
        },
        publicPath: "/",
        contentBase: resolve('../dist/index.html'), // boolean | string | array, static file location
        compress: true, // enable gzip compression
        port: 3333,
        open: true,
        // historyApiFallback: true, // true for index.html upon 404, object for multiple paths
        hot: true, // hot module replacement. Depends on HotModuleReplacementPlugin
        after: function(app, server, compiler) {
          console.log(app, server, compiler);
        }
        // https: false, // true for self-signed, object for cert authority
        // noInfo: true, // only errors & warns on hot reload
        // ...
      },
    
      plugins: [
        ...config.plugins,
        // 编译时(compile time)插件
        // webpack-dev-server 强化插件
        new DashboardPlugin(),
        new webpack.HotModuleReplacementPlugin(),
      ]
    }
    
    // webpack.pro.js
    const TerserPlugin = require('terser-webpack-plugin');
    const webpack = require('webpack');
    
    const config = require('./webpack.base');
    
    process.env.NODE_ENV = 'production';
    
    module.exports = {
      ...config,
      mode: 'production',
      devtool: "enum", // enum  // 通过在浏览器调试工具(browser devtools)中添加元信息(meta info)增强调试
      // 牺牲了构建速度的 `source-map' 是最详细的。
      // context: __dirname, // string(绝对路径!)
      // webpack 的主目录
      // entry 和 module.rules.loader 选项
      // 相对于此目录解析
    
      // target: "web", // 枚举  // 包(bundle)应该运行的环境
      // 更改 块加载行为(chunk loading behavior) 和 可用模块(available module)
      stats: "errors-only",  // 精确控制要显示的 bundle 信息
      optimization: {
        splitChunks: {
          cacheGroups: {
            commons: {
              name: "vendor",
              filename: 'vendor-[hash].min.js',
              minChunks: 2
            }
          }
        },
        minimizer: [
          new TerserPlugin({
            cache: true, // 开启缓存
            parallel: true, // 支持多进程
            sourceMap: true,
          }),
        ]
      },
      plugins: [
        ...config.plugins,
        new webpack.DefinePlugin({
          'process.env.NODE_ENV': '"development"',
        }),
        // 构建优化插件,下面两个在最新的webpack中已经被挪进了配置中
        // new webpack.optimize.CommonsChunkPlugin({
        //   name: 'vendor',
        //   filename: 'vendor-[hash].min.js',
        // }),
        // new webpack.optimize.UglifyJsPlugin({
        //   compress: {
        //     warnings: false,
        //     drop_console: false,
        //   }
        // }),
        new webpack.IgnorePlugin(/^./locale$/, /moment$/),
      ]
    }
    

    第三步,编写入口文件

    // index.jsx
    import React from "react";
    import ReactDOM from "react-dom";
    
    import HelloWorld from 'Components/test/HelloWorld';
    
    function render() {
      console.log(111);
      ReactDOM.render(
        <HelloWorld />,
        document.getElementById("root")
      );
    }
    
    render();
    

    完成了,最基本的React项目的构建已经完成,后续可以针对自己的项目需要添加适当的配置。

    遇到了哪些问题。

    1. 由于使用的webpack版本太新了,很多配置都变了。
    • 比如webpack.optimize.CommonsChunkPlugin变成了webpack配置项optimization.splitChunks
    • webpack.optimize.UglifyJsPlugin变成了webpack配置项optimization.minimizer
    • extract-text-webpack-plugin不兼容4.0之后的webpack,所以我找了mini-css-extract-plugin来替代它。
    1. webpack-dev-server开启时需要指定它的config文件,如webpack-dev-server --config config/webpack.dev.js

    完整的demo示例可以去我的github上查看,这个demo的地址是https://github.com/810307015/ReactDemo

    后续,后面可能要在里面加入多级路由,redux的相关配置,目前这个版本用来做最基础的演示已经足够了。

    最后,如果你看到了这里,还不是直接滑到了底部,那么非常感谢你的阅读,希望你能点个订阅,评论一下,点个赞啥的。

  • 相关阅读:
    中考 2020 游记
    CodeChef 2020 July Long Challenge 题解
    GDOI2020 游记
    AtCoder Grand Contest 044 题解
    ISIJ2020 不知道算不算游记
    WC2020 拿铁记
    UOJ Round 19 题解
    本博客采用 CC BY-NC-SA 4.0 进行许可
    [算法模版]回文树
    AddressSanitizer
  • 原文地址:https://www.cnblogs.com/aloneMing/p/12956340.html
Copyright © 2020-2023  润新知