zoukankan      html  css  js  c++  java
  • 从零开始,构建属于自己的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的相关配置,目前这个版本用来做最基础的演示已经足够了。

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

  • 相关阅读:
    Java对象的生命周期与作用域的讨论(转)
    [置顶] Oracle学习路线与方法
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 未名湖边的烦恼
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
    Java实现 蓝桥杯 算法训练 最大的算式
  • 原文地址:https://www.cnblogs.com/aloneMing/p/12956340.html
Copyright © 2011-2022 走看看