Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create React App 的Webpack4配置高级进阶 #3

Open
sisterAn opened this issue Feb 16, 2019 · 0 comments
Open

Create React App 的Webpack4配置高级进阶 #3

sisterAn opened this issue Feb 16, 2019 · 0 comments

Comments

@sisterAn
Copy link
Owner

React 框架搭建

Creact React App(CRA)是创建React应用的一个构建脚本,并不处理后端逻辑及数据库,它与其他构建脚本不同的一点就是,它使用了 Babel 和 Webpack 这样的构建工具,使开发者不用单独去配置这些工具,从而降低了开发人员的学习难度。
但对于一些高阶的开发人员,想要对Webpack做一些修改,包括对less、跨域访问的支持以及antd的配置等,下面就是我的具体做法。
注意当前webpack的版本"webpack": "4.19.1",时基于此给出的解决方案,webpack至少是4以上版本。
按照React 官网创建你的React项目,这里就不在讲解。
使用CRA创建好项目之后,打开package.json文件:

  {
  ...
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  ...
}

执行yarn eject将封装到CRA中的全部配置反编译到当前项目,由此webpack的配置全部暴露给了开发者。

// eject 后项目根目录下会出现 config 文件夹,里面就包含了 webpack 配置
config
├── env.js
├── jest
│   ├── cssTransform.js
│   └── fileTransform.js
├── paths.js
├── webpack.config.dev.js // 开发环境配置
├── webpack.config.prod.js // 生产环境配置
└── webpackDevServer.config.js
// eject 后项目根目录下会出现 scripts 文件夹,里面就包含了 项目启动文件
├── build.js //生产环境
├── start.js // 开发环境
├── test.js // 测试环境

CRA和其他构建脚本不同的是,它可以通过升级react-scripts来升级CRA特性,但是如果使用eject命令后,就无法使用了,因为react-scripts已经是以文件的形式存在于你的项目,而不是以包的形式,所以无法对其升级。

Webpack配置

这时,一个简单的项目已经可以运行成功了并且webpack配置暴露了出来,下面安装antd,配置antd

1. antd

yarn add antd安装后,你可以使用antd的组件,官网提供了两种配置方案,我们这里只介绍eject配置。

  • 配置less,antd 的样式使用了 Less 作为开发语言,安装yarn add lessyarn add less-loader
  • 按需加载,yarn babel-plugin-import 是一个用于按需加载组件代码和样式的 babel 插件
  • 自定义主题
    打开webpack.config.dev.js,作出相应的修改:
...
// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
//--------------------注意:这里需要增加less的相关配置--------------------
const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;

// common function to get style loaders
const getStyleLoaders = (cssOptions, preProcessor) => {
 ...
 // --------------------注意,在此处修改了判断语句的代码,增加对less的支持--------------------
 if (preProcessor) {
     if (preProcessor === 'less-loader') {
         loaders.push({
             loader:require.resolve(preProcessor),
             options: {
                 modules: false,
                 modifyVars: {
                     "@primary-color": "#1890ff" // 这里配置antd的自定义主题色
                 },
                 javascriptEnabled: true
             }
         })
     } else {
         loaders.push(require.resolve(preProcessor));
     }
 }
 return loaders;
 };
 // This is the development configuration.
 // It is focused on developer experience and fast rebuilds.
 // The production configuration is different and lives in a separate file.
 module.exports = {
 ...
 module: {
 strictExportPresence: true,
 rules: [
   ...
   {
     // "oneOf" will traverse all following loaders until one will
     // match the requirements. When no loader matches it will fall
     // back to the "file" loader at the end of the loader list.
     oneOf: [
       ...
       // Process application JS with Babel.
       // The preset includes JSX, Flow, and some ESnext features.
       {
         test: /\.(js|mjs|jsx|ts|tsx)$/,
         include: paths.appSrc,
         loader: require.resolve('babel-loader'),
         options: {
           customize: require.resolve(
             'babel-preset-react-app/webpack-overrides'
           ),
           
           plugins: [
             [
               require.resolve('babel-plugin-named-asset-import'),
               {
                 loaderMap: {
                   svg: {
                     ReactComponent: '@svgr/webpack?-prettier,-svgo![path]',
                   },
                 },
               },
             ],
             // --------------------注意此处增加:实现按需加载--------------------: 
               ['import', { libraryName: 'antd', style: true }],  // import less
           ],
           // This is a feature of `babel-loader` for webpack (not Babel itself).
           // It enables caching results in ./node_modules/.cache/babel-loader/
           // directory for faster rebuilds.
           cacheDirectory: true,
           // Don't waste time on Gzipping the cache
           cacheCompression: false,
         },
       },
       ...
       // --------------------注意此处在cssRegex配置之上增加--------------------
         // "postcss" loader applies autoprefixer to our CSS.
         // "css" loader resolves paths in CSS and adds assets as dependencies.
         // "style" loader turns CSS into JS modules that inject <style> tags.
         // In production, we use a plugin to extract that CSS to a file, but
         // in development "style" loader enables hot editing of CSS.
         // By default we support CSS Modules with the extension .module.css
         {
             test: lessRegex,
             exclude: lessModuleRegex,
             use: getStyleLoaders({
                 importLoaders: 2,
             }, 'less-loader'),
         },
         // Adds support for CSS Modules (https://github.com/css-modules/css-modules)
         // using the extension .module.css
         {
             test: lessModuleRegex,
             use: getStyleLoaders({
                 importLoaders: 2,
                 modules: true,
                 getLocalIdent: getCSSModuleLocalIdent,
             },  'less-loader'),
         },
       // "postcss" loader applies autoprefixer to our CSS.
       // "css" loader resolves paths in CSS and adds assets as dependencies.
       // "style" loader turns CSS into JS modules that inject <style> tags.
       // In production, we use a plugin to extract that CSS to a file, but
       // in development "style" loader enables hot editing of CSS.
       // By default we support CSS Modules with the extension .module.css
       {
         test: cssRegex,
         exclude: cssModuleRegex,
         use: getStyleLoaders({
           importLoaders: 1,
         }),
       },
       // Adds support for CSS Modules (https://github.com/css-modules/css-modules)
       // using the extension .module.css
       {
         test: cssModuleRegex,
         use: getStyleLoaders({
           importLoaders: 1,
           modules: true,
           getLocalIdent: getCSSModuleLocalIdent,
         }),
       },
       ...
     ],
   },
   ...
   // ** STOP ** Are you adding a new loader?
   // Make sure to add the new loader(s) before the "file" loader.
 ],
 },
 ...
 };

同样,对webpack.config.prod.js做相同的调整。
至此,antd配置结束。

2. 跨域-- webpack-dev-server

webpack-dev-server 为你提供了一个简单的 web 服务器,并且能够实时重新加载(live reloading)。
在eject之后暴露出来的scripts/start.js, 找到

...
const paths = require('../config/paths');
...
// We require that you explictly set browsers and do not fall back to
// browserslist defaults.
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
  .then(() => {
    // We attempt to use the default port but if it is busy, we offer the user to
    // run on a different port. `choosePort()` Promise resolves to the next free port.
    // 获取端口号
    return choosePort(HOST, DEFAULT_PORT);
  })
  .then(port => {
    if (port == null) {
      // We have not found a port.
      return;
    }
    // 获取协议类型
    const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
    // 获取名称
    const appName = require(paths.appPackageJson).name;
    // 获取url
    const urls = prepareUrls(protocol, HOST, port);
    // 根据惯用的信息创建一个webpack编译器
    const compiler = createCompiler(webpack, config, appName, urls, useYarn);
    // **加载代理**-----------
    const proxySetting = require(paths.appPackageJson).proxy;
    const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
    // 创建WebpackDevServer服务器
    const serverConfig = createDevServerConfig(
      proxyConfig,
      urls.lanUrlForConfig
    );
    const devServer = new WebpackDevServer(compiler, serverConfig);
    // 启动WebpackDevServer服务器
    devServer.listen(port, HOST, err => {
      if (err) {
        return console.log(err);
      }
      if (isInteractive) {
        clearConsole();
      }
      console.log(chalk.cyan('Starting the development server...\n'));
      openBrowser(urls.localUrlForBrowser);
    });

    ['SIGINT', 'SIGTERM'].forEach(function(sig) {
      process.on(sig, function() {
        devServer.close();
        process.exit();
      });
    });
  })
  .catch(err => {
    if (err && err.message) {
      console.log(err.message);
    }
    process.exit(1);
  });

注意 加载代理配置项proxySetting,它是由paths.appPackageJson加载来的,我们向上找到const paths = require('../config/paths');

...
// config after eject: we're in ./config/
module.exports = {
dotenv: resolveApp('.env'),
appPath: resolveApp('.'),
appBuild: resolveApp('build'),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveModule(resolveApp, 'src/index'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
appTsConfig: resolveApp('tsconfig.json'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
// -------加载代理配置栏------
proxySetup: resolveApp('src/setupProxy.js'),
appNodeModules: resolveApp('node_modules'),
publicUrl: getPublicUrl(resolveApp('package.json')),
servedPath: getServedPath(resolveApp('package.json')),
};
...

查找当前src文件夹

src
├── App.css
├── App.js
├── App.test.js
├── index.css
├──index.js
├── logo.svg
└── serviceWorker.js

并没有setupProxy.js文件,我们创建src/setupProxy.js,并安装yarn add http-proxy-middleware,设置相应的代理

// src/setupProxy.js 配置代理
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
    app.use(proxy('/api/',
        {
            target: 'https://api.dev.com',// 后端服务器地址
            changeOrigin: true,
            secure: false
        }
    ));
}

更多devServer的配置,详见开发中 Server(devServer),这里不在详细介绍。

至此,若后续有修改,将继续更新。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant