14

As a command-line tool officially maintained by React, create-react-app (CRA for short) makes it extremely easy to create fully-configured React applications, helping users quickly enter React development. Its biggest shortcoming is that the application created cannot be customized as desired. If you want to customize, you can only eject . And eject means that all the configuration of the application is maintained by the user, which is tedious and prohibitive.

Now, with wuzzle , we can arbitrarily customize the React app created by CRA without ejecting.

View CRA webpack configuration without eject

First, use CRA to create a demo application that supports TypeScript (if you are not used to using TS to remove parameters --template typescript ):

 $ npx create-react-app --template typescript demo
# ...
$ cd demo

Install wuzzle:

 $ npm i -D wuzzle

Open package.json edit scripts mount wuzzle:

 "scripts": {
-    "start": "react-scripts start",
+    "start": "wuzzle react-scripts start",
-    "build": "react-scripts build",
+    "build": "wuzzle react-scripts build",
  },

Now, run start or build script with the parameters --dry-run to directly view the webpack configuration used inside the CRA:

 $ npm run build -- --dry-run
# ...
@wuzzle/cli:applyConfig Webpack config with difference: {
  # ...
  devtool: # ...
  entry: # ...
  output: #...
  cache: #...
  resolve: # ...
  module: # ...
  plugins: # ...
  # ...
}

Introduce less and use antd without eject

On style files, CRA applications support css, scss/sass, but not less. If you want to fully use antd and make theme modifications, you need to introduce less in the webpack configuration. Go back to --dry-run run the result and take a closer look at the module field:

 $ npm run build -- --dry-run
# ...
@wuzzle/cli:applyConfig Webpack config with difference: {
  # ...
  module: {
    # ...
    rules: [
      # ...
      {
        oneOf: [
          # ...
          {
            test: /\.(scss|sass)$/,
            exclude: /\.module\.(scss|sass)$/,
            use: [
              {
                loader: '.../mini-css-extract-plugin/dist/loader.js',
                options: {}
              },
              {
                loader: '.../css-loader/...',
                options: # ...
              },
              {
                loader: '.../postcss-loader/...',
                options: # ...
              },
              {
                loader: '.../resolve-url-loader/...',
                options: # ...
              },
              {
                loader: '.../sass-loader/...',
                options: # ...
              }
            ],
          },
          {
            test: /\.module\.(scss|sass)$/,
            use: [
              {
                loader: '.../mini-css-extract-plugin/dist/loader.js',
                options: # ...
              },
              {
                loader: '.../css-loader/...',
                options: # ...
              },
              {
                loader: '.../postcss-loader/...',
                options: # ...
              },
              {
                loader: '.../resolve-url-loader/...',
                options: # ...
              },
              {
                loader: '.../sass-loader/...',
                options: # ...
              }
            ]
          },
          # ...
        ]
      }
    ]
  },
  # ...
}

It is not difficult to find that the configuration method of sass is very close to that of less. With a little modification, replace sass-loader with less-loader and remove resolve-url-loader to achieve the goal.

Install the dependencies required to configure less:

 npm i -D less less-loader

Then, create a file next to package.json wuzzle.config.js to modify the webpack configuration used inside the CRA. Here you can use the modification help method provided by wuzzle to reduce the workload:

 const appPaths = require('react-scripts/config/paths');
const { deleteUseItem, firstRule, firstUseItem, replaceUseItem } = require('wuzzle');

module.exports = (webpackConfig, webpack, wuzzleContext) => {
  const { commandArgs } = wuzzleContext;

  if (commandArgs[0] === 'start' || commandArgs[0] === 'build') {
    // Replace sass-loader with less-loader to support .less files
    const lessOptions = { javascriptEnabled: true };

    const scssRuleQuery = { file: { dir: appPaths.appSrc, base: 'index.scss' } };
    const lessRule = firstRule(webpackConfig, scssRuleQuery);
    Object.assign(lessRule, { test: /\.(less)$/, exclude: /\.module\.less$/ });
    deleteUseItem(lessRule, { loader: 'resolve-url-loader' });
    replaceUseItem(
      lessRule,
      { loader: 'sass-loader' },
      { loader: 'less-loader', options: { sourceMap: true, lessOptions } }
    );
    firstUseItem(lessRule, { loader: 'css-loader' }).options.importLoaders = 2;

    const scssModuleRuleQuery = { file: { dir: appPaths.appSrc, base: 'index.module.scss' } };

    const lessModuleRule = firstRule(webpackConfig, scssModuleRuleQuery);
    Object.assign(lessModuleRule, { test: /\.module\.less$/ });
    deleteUseItem(lessModuleRule, { loader: 'resolve-url-loader' });
    replaceUseItem(
      lessModuleRule,
      { loader: 'sass-loader' },
      { loader: 'less-loader', options: { sourceMap: true, lessOptions } }
    );
    firstUseItem(lessModuleRule, { loader: 'css-loader' }).options.importLoaders = 2;
  }
};

After that, change all .css file suffixes to .less :

  • index.css重命名index.lessindex.tsximport './index.css';改为import './index.less';
  • App.css重命名App.lessApp.tsximport './App.css';改为import './App.less';

Install antd:

 $ npm i -S antd

In index.less introduce the antd style file:

 -body {
-  ...
-}
-code {
-  ...
-}
+@import '~antd/dist/antd.less';

If you want to modify the antd theme, you can go back to wuzzle.config.js lessOptions and add the modifyVars field in ---6e4beec2179e09b104827bbec4156cad---, for example:

 -    const lessOptions = { javascriptEnabled: true };
+    const lessOptions = {
+      javascriptEnabled: true,
+      modifyVars: { '@primary-color': '#1da57a' },
+    };

Now, run the start or build script to see the effect of introducing less and using antd in the CRA application:

 $ npm start
Starting the development server...
Compiled successfully!

You can now view demo in the browser.

  Local:            http://localhost:3000
  On Your Network:  http://192.168.100.24:3000

Note that the development build is not optimized.
To create a production build, use npm run build.

webpack compiled successfully
No issues found.

Adjust CRA test configuration without eject

Internally, CRA test is packaged based on jest, not webpack. For jest, wuzzle provides two ways to customize the configuration:

  1. Replacing the compilation of jest itself with the compatible wepback compilation, and the user modifies the webpack compilation configuration.
  2. Continue to use jest's own compilation, and users modify the jest compilation configuration.

Let's see how to introduce less to maintain test script compatibility through these two methods.

method 1

Go back to package.json , edit scripts to test and mount the script on wuzzle:

 "scripts": {
-    "test": "react-scripts test",
+    "test": "wuzzle react-scripts test",
  },

Then, run the test --dry-run to view the configuration of the webpack compiled instead of jest itself:

 $ npm test -- --dry-run
# ...
@wuzzle/cli:applyConfig Webpack config with difference: {
  # ...
  module: {
    rules: [
      {
        test: /\.(js|jsx|mjs|cjs|ts|tsx)$/,
        exclude: /node_modules/,
        use: # ...
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [
          {
            loader: '.../null-loader/...'
          }
        ]
      },
      {
        test: /\.svg$/,
        exclude: /node_modules/,
        use: # ...
      },
      {
        exclude: [ /\.(js|jsx|mjs|cjs|ts|tsx|json|css|svg)$/, /node_modules/ ],
        use: # ...
      }
    ]
  },
  # ...
}

It can be found that as long as the matching of the .less file is added to the css configuration, and the matching of the .less configuration.

Go back to wuzzle.config.js and modify the configuration of webpack compilation that replaces jest's own compilation:

 module.exports = (webpackConfig, webpack, wuzzleContext) => {
  const { commandArgs } = wuzzleContext;

  // ...

+  if (commandArgs[0] === 'test') {
+    const cssRule = firstRule(webpackConfig, { file: 'index.css' });
+    cssRule.test = [cssRule.test, /\.less$/];
+
+    const fallbackRule = firstRule(webpackConfig, { file: 'index.fallback' });
+    fallbackRule.exclude.push(/\.less$/);
+  }
};

Now, run the test script to see the effect of introducing less in CRA test:

 $ npm test
# ...
File 'src/setupTests.ts' compiled.
File 'src/App.test.tsx' compiled.
File 'src/App.tsx' compiled.
File 'src/App.less' compiled.
File 'src/logo.svg' compiled.
 PASS  src/App.test.tsx (10.183 s)
  ✓ renders learn react link (40 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        11.005 s
Ran all test suites related to changed files.

Method 2

Go back to package.json , edit again scripts test script add parameters --no-webpack close webpack

 "scripts": {
-    "test": "wuzzle react-scripts test",
+    "test": "wuzzle react-scripts test --no-webpack",
  },

Then, run the test script through the parameter --dry-run to view the configuration compiled by jest itself:

 $ npm test -- --dry-run
# ...
@wuzzle/cli:applyConfig Jest config with difference: {
  # ...
  transform: [
    [
      '^.+\\.(js|jsx|mjs|cjs|ts|tsx)$',
      '.../node_modules/react-scripts/config/jest/babelTransform.js',
      {}
    ],
    [
      '^.+\\.css$',
      '.../node_modules/react-scripts/config/jest/cssTransform.js',
      {}
    ],
    [
      '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)',
      '.../node_modules/react-scripts/config/jest/fileTransform.js',
      {}
    ]
  ],
  # ...
}

This configuration is slightly different from the user configuration of jest. It is the configuration used internally by jest. The structure refers toProjectConfig . Similar to method 1, just add the matching pair .less file in the css configuration, and remove the matching pair .less file in the bottom configuration.

Go back to wuzzle.config.js , first create a new object and put the original direct export method into the modify field export:

 module.exports = {
  modify(webpackConfig, webpack, wuzzleContext) {
    // Place the directly exported top-level function here.
  },
};

After that, continue to wuzzle.config.js add jest field to modify the jest compilation configuration:

 module.exports = {
  modify(webpackConfig, webpack, wuzzleContext) { // ...
  },

+  jest(jestConfig, jestInfo, wuzzleContext) {
+    for (const transformItem of jestConfig.transform) {
+      const fileRegExp = new RegExp(transformItem[0]);
+      if (fileRegExp.test('index.css')) {
+        transformItem[0] = '^.+\\.(css|less)$';
+      }
+      if (fileRegExp.test('index.fallback')) {
+        transformItem[0] = '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|less|json)$)';
+      }
+    }
+  },
};

Now, run the test script to see the same effect of introducing less in CRA test. The difference is that performance may be better because webpack compilation is turned off.

Further customization

Up to this point, all the scripts of the CRA application have been customized, and the eject script is no longer needed, and can be edited package.json :

 "scripts": {
-    "eject": "react-scripts eject",
  }

In real projects, SSR (server-side rendering), E2E (end-to-end testing), and in-depth configuration of eslint may also be used. For how to use CRA and wuzzle to further build a real application, you can refer to the official examplee2e/.../react-scripts .

write at the end

At present, the example project in the article has been included in wuzzle-blog/.../demo , readers and friends can open the reference as needed. If you have any questions or ideas, please leave a message. In addition, if you have any questions or ideas about wuzzle, you are welcome to create an issue in wuzzle/issues , both in Chinese and English. If you are interested and have time to contribute code, please submit PR. For details, please refer to the development guide . Finally, if you think the gadget is helpful, you can order a small ⭐️ in the GitHub repo wuzzle to compare your heart.

read more

Wuzzle, for webpack-based JS translation


乌柏木
2.2k 声望1.1k 粉丝

认真写点好代码。