React + Webpack (jsx +less)

Posted System.print("宇航")

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React + Webpack (jsx +less)相关的知识,希望对你有一定的参考价值。

React项目的初始化、webpack的安装、如何使用jsx和less。

一、初始 React 项目

  react项目的初始化比较简单,我用的就是react的脚手架。三种方式

  1、NPM

npm init react-app my-app

  2、NPX

npx create-react-app my-app

  3、Yarn

yarn create react-app my-app

 

  my-app 是项目的名字,运行命令时会在当前目录下自动创建一个名字叫作 my-app 的项目文件夹。命令运行完毕,简单的React项目就初始化完成了。项目的初始的代码结构式这个样子的:

  进入项目文件,你可以通过 npm run start 来运行项目,会跳出一个React的欢迎页

my-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    └── serviceWorker.js

 

二、Webpack安装程序

  Webpack

    WebPack可以看做是模块打包机:它会分析你的项目结构,找到javascript模块以及其它的一些浏览器不能直接运行的拓展语言(less、jsx、Scss、TypeScript等),并将其打包为合适的格式以供浏览器使用。

  为什么要用 WebPack ?

    1、模块化

      在webpack看来一切都是模块!这就是它不可不说的优点,包括你的JavaScript代码,也包括CSS和fonts以及图片等等等,只有通过合适的loaders,它们都可以被当做模块被处理。

    2、预处理(Less,Sass,ES6,TypeScript……)

    3、主流框架脚手架支持(Vue,React,Angular)

    4、庞大的社区(资源丰富,降低学习成本)

  

  1、开始安装Webpack

    使用 webpack 首先你需要安装 webpack-dev-server 在本地环境中为捆绑的应用程序提供服务、webpack-cli 在配置文件中来配置你的Webpack 设置。

npm install --save-dev webpack webpack-dev-server webpack-cli

  

  2、修改 package.json

     主要修改 package.json 中的启动项

       

"scripts": {
  "start": "webpack-dev-server --config config/webpack.base.config.js --mode development",
  ...
}

        

    脚本将 webpack-dev-server 与名为 webpack.base.config.js 一起使用。我在项目的根目录下创建了一个 config 文件夹,里面用来存放 webpack 的配置文件。The --mode development flag just adds default Webpack configurations which came with Webpack 4.

      

  

  3、编辑 webpack.base.config.js

module.exports = {
    entry: \'./src/index.js\',
    output: {
      path: __dirname + \'/public\',
      publicPath: \'/\',
      filename: \'bundle.js\'
    },
    devServer: {
      contentBase: \'./public\'
    }
};

    文件说明:

      (1) 我们希望使用 “./src/index.js” 文件作为入口点。

      (2) 绑定的文件最后生成的js文件,叫做: bundle.js .

      (3)生成的位置在:“/public”

  

  4、修改一下public/index.html 和 src/index.js 中的内容

    因为我们初步使用 webpack 来启动我们的项目,所以像是 svg图片react的识别都还没有配置。所以先将这两个文件进行修改,这些修改不会影响到之后咱们的搭建。将两个文件修改成下面的样子。

    public/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>React App</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <base href="/">
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <script src="./bundle.js"></script>
  </body>
</html>

    src/index.js

console.log(\'My Minimal React Webpack Babel Setup\');

  5、npm start

    OK,我们已经使用 webpack 将项目的启动脚本配置好了。下面就是使用 npm start 来验证我们的启动命令是否成功。   

    

    项目启动成功,接下来访问地址 localhost:8080 来访问一下。

    

    其中我们在 src/index.js 里面 console.log 的信息已经显示在了浏览器里边,说明 index.js 已经通过 webpack 编译成了 bundle.js。

 

三、配置 babel

  babel 是一个广泛的转码器可以将 ES6 代码转化为 ES5 代码。从而在现有的环境中执行。

  1、安装插件

    在项目根目录下指定下面命令,作用是使得 babel 正常执行:

npm install --save-dev @babel/core @babel/preset-env

     为了将它连接到Webpack,还需要安装一个加载器:

npm install --save-dev babel-loader

     还需要一个配置,来将 React 的 jsx 语法转化成 JavaScript:

npm install --save-dev @babel/preset-react

  2、编辑 webpack.base.config.js 文件

    在 webpack.base.config.js 文件中添加代码:

    module: {
      rules: [
          {
              test: /\\.(js|jsx)$/,
              exclude: /node_modules/,
              use: [\'babel-loader\', \'eslint-loader\']
          },
          {
              test: /\\.(css|less)$/,
              use:["style-loader", "css-loader", "less-loader"]
          },
          {
              test: /\\.svg$/,
              use: [\'file-loader\']
          }
      ]
    },
    resolve: {
      extensions: [\'*\', \'.js\', \'.jsx\', \'.css\', \'.less\']
    }

 

   

    这些代码的作用是 是代码识别 js、jsx、css、less、svg图片文件的。

    这里要下载几个 loader 和 plugin:

npm install --save-dev style-loader css-loader less less-loader eslint-loader file-loader extract-text-webpack-plugin@next

    在项目根目录下创建 .babelrc 文件

      .babelrc

{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ]
}

  3、修改 src/index.js 文件

    webpack 已经认less和css文件了。现在我们修改一下index.js

import React from \'react\';
import ReactDOM from \'react-dom\';
import \'./index.css\';
import App from \'./App\';
import * as serviceWorker from \'./serviceWorker\';

ReactDOM.render(<App />, document.getElementById(\'root\'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: http://bit.ly/CRA-PWA
serviceWorker.unregister();

  然后将 App.css 改名为 App.less, 内容不需要改,如下图:

  

  OK,现在执行命令 npm start,访问 localhost:8080 看一下结果.

  

  成功。

 

四、使用 webpack 打包项目

  1、首先我在 config 文件夹中创建 path.js、webpack.opt.config.js、 webpack.prod.config.js 三个文件

    path.js

      path 的作用是 提供path路径的,自定义的path。

var path = require(\'path\');
var fs = require(\'fs\');

// Make sure any symlinks in the project folder are resolved:
// https://github.com/facebookincubator/create-react-app/issues/637
var appDirectory = fs.realpathSync(process.cwd());
function resolveApp(relativePath) {
  return path.resolve(appDirectory, relativePath);
}

// We support resolving modules according to `NODE_PATH`.
// This lets you use absolute paths in imports inside large monorepos:
// https://github.com/facebookincubator/create-react-app/issues/253.

// It works similar to `NODE_PATH` in Node itself:
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders

// We will export `nodePaths` as an array of absolute paths.
// It will then be used by Webpack configs.
// Jest doesn\'t need this because it already handles `NODE_PATH` out of the box.

// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
// Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
// https://github.com/facebookincubator/create-react-app/issues/1023#issuecomment-265344421

var nodePaths = (process.env.NODE_PATH || \'\')
  .split(process.platform === \'win32\' ? \';\' : \':\')
  .filter(Boolean)
  .filter(folder => !path.isAbsolute(folder))
  .map(resolveApp);

// config after eject: we\'re in ./config/
module.exports = {
  appBuild: resolveApp(\'build\'),
  appPublic: resolveApp(\'public\'),
  appHtml: resolveApp(\'public/index.html\'),
  appIndexJs: resolveApp(\'src/index.js\'),
  appPackageJson: resolveApp(\'package.json\'),
  appSrc: resolveApp(\'src\'),
  yarnLockFile: resolveApp(\'yarn.lock\'),
  appNodeModules: resolveApp(\'node_modules\'),
  nodePaths: nodePaths
};

    webpack.opt.config.js

      webpack.opt.config.js 是在打包时做 css代码 优化的

var OptimizeCssAssetsPlugin = require(\'optimize-css-assets-webpack-plugin\');
var UglifyJsPlugin = require(\'uglifyjs-webpack-plugin\');

module.exports = {
  optimization: {
    minimizer: [
      new UglifyJsPlugin({
        uglifyOptions: {
          mangle: {
            keep_fnames: true,
          },
        },
      })
    ],
  },
  plugins: [
    new OptimizeCssAssetsPlugin()
  ],
}

    webpack.prod.config.js

      webpack.prod.config.js 用来将各个 config 文件融合到一起

var webpack = require(\'webpack\');
var merge = require(\'webpack-merge\');

var baseConfig = require(\'./webpack.base.config\');
var optimizationConfig = require(\'./webpack.opt.config\');

const productionConfiguration = function (env) {
  const NODE_ENV = env.NODE_ENV ? env.NODE_ENV : \'development\';
  return {
    plugins: [
      new webpack.DefinePlugin({ \'process.env.NODE_ENV\': JSON.stringify(NODE_ENV) }),
    ]
  };
}

module.exports = merge.smart(baseConfig, optimizationConfig, productionConfiguration);  

    安装  uglifyjs-webpack-plugin 和 webpack-merge :

npm install --save-dev uglifyjs-webpack-plugin
 npm install --save-dev webpack-merge

  

  2、在项目根目录下创建 server 文件夹

    server 的作用是,打包成功之后,项目启动一个server。可以通过访问 server 地址来直接访问项目build之后生成的包。

      server/index.js

const express = require(\'express\');
const path = require(\'path\');
const http = require(\'http\');

const app = express();

// Point static path to dist
app.use(express.static(path.join(__dirname, \'..\', \'build\')));

const routes = require(\'./routes\')
app.use(\'/\', routes);

/** Get port from environment and store in Express. */
const port = process.env.PORT || \'3000\';
app.set(\'port\', port);

/** Create HTTP server. */
const server = http.createServer(app);
/** Listen on provided port, on all network interfaces. */
server.listen(port, () => console.log(`Server Running on port ${port}`))

 

      routes/index.js

const path = require(\'path\');
const router = require(\'express\').Router();

router
  .get(\'/*\', (req, res, next) => {
    const routePath = path.join(__dirname + \'..\', \'..\', \'..\',\'build/\' + \'index.html\');
    res.sendFile(routePath);
  })
module.exports = router;

 

    这里面要安装一个 express:  

npm install --save-dev express  

 

 

    

 

  3、修改 webpack.base.config.js

    webpack.base.config.js 最终版

const webpack = require(\'webpack\');
var HtmlWebpackPlugin = require(\'html-webpack-plugin\');
var ExtractTextPlugin = require(\'extract-text-webpack-plugin\');
var paths = require(\'./paths\');

module.exports = {
    entry: \'./src/index.js\',
    output: {
      path: paths.appBuild,
      publicPath: \'/\',
      filename: \'bundle.js\'
    },
    module: {
        rules: [
            {
                test: /\\.(js|jsx)$/,
                exclude: /node_modules/,
                use: [\'babel-loader\', \'eslint-loader\']
            },
            {
                test: /\\.(css|less)$/,
                use:["style-loader", "css-loader", "less-loader"]
                // use: ExtractTextPlugin.extract({
                //   fallback: "style-loader",
                //   use: "css-loader!less-loader",
                // })
            },
            {
                test: /\\.svg$/,
                use: [\'file-loader\']
            }
        ]
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new HtmlWebpackPlugin({ 
            template: \'./public/index.html\', 
            filename: \'./index.html\' 
        }),
        new ExtractTextPlugin(\'style.css\')
    ],
    resolve: {
        extensions: [\'*\', \'.js\', \'.jsx\', \'.css\', \'.less\']
    },
    devServer: {
      contentBase: \'./public\',
      hot: true
    }
  };

    标红的部分是两种 css 的 load 方式。

      直接使用 " use: [] " : 打包时,css会被打包到 bundle.js 里面。

      使用 " use: ExtractTextPlugin.extract() " : plugin 中的 new ExtractTextPlugin(\'style.css\') 联用。打包时会将css文件分离开来进行打包,在 build 文件夹中生成一个 style.css 文件.

    安装 html-webpack-plugin:

npm install --save-dev html-webpack-plugin 

  4、package.json

     script 中的 build 换成如下语句

"prestart:prod": "webpack --mode production --config config/webpack.prod.config.js --env.NODE_ENV=production --progress",
    "start:prod": "node server",

    

 

  5测试

    OK,全部配置完毕了,下面我们来测试一下是否成功。

      运行命令 npm run start:prod 

     

      build 生成的文件,三个如下:

             

      运行成功,访问 localhost:3000 访问 build 好的包。

     

       

      执行命令: npm start

    

      

      访问 localhost:8080:

    

 

 

 

 

 

 

 

 

 

 

    

 

以上是关于React + Webpack (jsx +less)的主要内容,如果未能解决你的问题,请参考以下文章

创建react项目并配置webpack

react+webpack+scss 怎么编译css独立文件

React开发环境搭建(react,babel,webpack webpack-dev-server)

create-react-app 如何查看webpack配置

webpack学习—webpack+react+es6

React 使用webpack构建React项目