Webpack4+Babel7+React16+Less简单配置笔记

1,124 阅读4分钟

Webpack4+Babel7+React16+Less简单配置笔记

一、项目初始化

新建一个项目react-init

mkdir react-init
cd react-init

初始化

yarn init -y
# 或
npm init -y

二、安装Webpack

webpack4的安装需要安装两个,一个是webpack,另外就是webpack-cli

yarn add webpack webpack-cli -D
# 或
npm i webpack webpack-cli -D

三、建立webpack配置文件

在项目根目录下面创建config目录,并在该目录里面建3个配置文件,分别是:

webpack.base.conf.js —— 共有配置

webpack.dev.conf.js —— 开发环境配置

webpack.prod.conf.js —— 生产环境配置

因为使用了公共的配置项,所以为了能够使用公共项,需要引入另外一个库,安装如下:

yarn add webpack-merge -D
# 或
npm i webpack-merge -D

在webpack.base.conf.js里面写入:

const path = require('path');
const DIST_PATH = path.resolve(__dirname, '../dist');
const APP_PATH = path.resolve(__dirname, '../src');

module.exports = {
  entry: {
    app: APP_PATH+'/index.js'
  },
  output: {
    filename: "js/[name].[chunkhash].js",
    path: DIST_PATH
  },
  resolve: {
    extensions: [".js", ".jsx", ".less"],
    alias: {
      "@": APP_PATH
    }
  },
}

在webpack.dev.conf.js里面写入:

const path = require("path");
const merge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");

module.exports = merge(baseWebpackConfig, {
  mode: "development",
  output: {
    filename: "js/[name].[hash:16].js"
  },
  devtool: "inline-source-map",
});

在webpack.prod.conf.js里面写入:

const merge = require("webpack-merge");
const baseWebpackConfig = require("./webpack.base.conf");

module.exports = merge(baseWebpackConfig, {
  mode: "production",
});

在根目录下面创建src目录,然后创建index.js文件,作为整个项目的入口文件,创建App.jsx文件,作为react项目的根组件;

在根目录下面创建public目录,然后创建index.html文件,作为整个单页项目的模板文件;

index.html内容如下:

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <!-- <title><%= htmlWebpackPlugin.options.title %></title> -->
    <title>React-Init</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>

在package.json里面,添加命令行脚本:

"scripts": {
  "build": "webpack --config config/webpack.prod.conf.js"
 }

四、安装React

yarn add react react-dom
# 或
npm i react react-dom -S

修改src/App.jsx文件如下:

import React, { Component } from "react";

class App extends Component {
  render() {
    return (
      <h1>Hello React</h1>
    );
  }
}

export default App;

修改src/index.js文件如下:

import React from "react";
import ReactDom from "react-dom";

import App from "./App";

ReactDom.render(<App />, document.getElementById("root"));

五、安装Babel

为了使ES6的模块化被支持以及能够转为浏览器识别的ES5代码,和JSX格式解析,必须引入对应的babel和babel插件,安装如下:

yarn add babel-loader @babel/core @babel/preset-env @babel/preset-react -D
# 或
npm i babel-loader @babel/core @babel/preset-env @babel/preset-react -D

配置babel:

在webpack.base.conf.js里面

module.exports = {
  ...
  resolve: {
    extensions: [".js", ".jsx", ".less"],
    alias: {
      "@": APP_PATH
    }
  },
  // 以下是添加的内容
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: 'babel-loader',
        include: APP_PATH
      },
    ]
  }
}

然后在根目录新建.babelrc文件,内容如下:

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

六、添加Html模板

安装html-webpack-plugin插件:

yarn add html-webpack-plugin -D
# 或
npm i html-webpack-plugin -D

这个可以将生成的JS文件自动加载到html的script标签内去,可以自定义html模板,具体看其在npm网站上的文档。

给webpack.prod.conf.js增加配置内容如下

...
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = merge(baseWebpackConfig, {
  mode: "production",
  plugins: [
    new HtmlWebpackPlugin({
      template: "public/index.html",
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      }
    })
  ]
});

此时,可以进行build了,运行

yarn build
# 或
npm run build

如果没有报错,且根目录下生成dist目录,则表示之前的配置基本上正确了

webpack优化

生产过程中,可以使用clean-webpack-plugin对dist文件夹先进行清理:

yarn add clean-webpack-plugin -D

然后在webpack.prod.conf.js里面增加如下内容:

...
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
...
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: "public/index.html",
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      }
    })
  ]
...

七、添加热加载开发环境

yarn add webpack-dev-server -D

在webpack.dev.conf.js里面添加:

...
const HtmlWebpackPlugin = require("html-webpack-plugin");
const webpack = require("webpack");

module.exports = merge(baseWebpackConfig, {
  ...
  plugins: [
    new HtmlWebpackPlugin({
      template: "public/index.html",
      inject: "body",
      minify: {
        html5: true
      },
      hash: false
    }),
    new webpack.HotModuleReplacementPlugin()
  ],
  devServer: {
    port: 3000,
    contentBase: path.join(__dirname, "../public"),
    compress: true,
    historyApiFallback: true,
    hot: true,
    https: false,
    noInfo: true,
    open: true,
    proxy: {}
  }
});

然后在package.json的脚本里面:

"scripts": {
  "build": "webpack --config config/webpack.prod.conf.js",
  "dev": "webpack-dev-server --inline --progress --config config/webpack.dev.conf.js"
}

执行

yarn dev
# 或
npm run dev

即可在打开的浏览器里面进行访问,地址为localhost:3000

八、对CSS和Less处理

使用webpack我们可以在js里面导入css或less文件,但是必须使用相应的loader才能进行处理。

yarn add css-loader mini-css-extract-plugin less less-loader postcss-loader autoprefixer -D

在webpack.base.conf.js里面添加

...
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
...
module.exports = {
  ...
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: "babel-loader",
        include: APP_PATH
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            options: {
              modules: true  // 使支持css modules
            }
          }
        ]
      },
      {
        test: /\.less$/,
        exclude: /node_modules/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: "css-loader",
            options: {
              modules: true
            }
          },
          {
            loader: "postcss-loader",
            options: {
              plugins: [require("autoprefixer")()]
            }
          },
          {
            loader: "less-loader",
            options: {
              modifyVars: {
                // 自定义的主题内容写在这里
              }
            }
          }
        ]
      },
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "css/[name].[hash].css",
      ignoreOrder: false
    })
  ]
};

为了使autoprefixer生效,需要在package.json里面添加如下内容:

"browserslist": [
  "last 4 version",
  "> 1%",
  "maintained node versions",
  "not dead"
]

九、对字体和图片进行处理

安装loader:

yarn add file-loader url-loader -D

在webpack.base.conf.js里面添加:

module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.(png|jpg|gif|jpeg|bmp|webp)$/,
        use: [
          {
            loader: "url-loader",
            options: {
              publicPath: "/",
              name: "images/[name].[ext]",
              limit: 512
            }
          }
        ]
      },
      {
        test: /\.(woff|svg|eot|woff2|tff)$/,
        use: "file-loader",
        exclude: /node_modules/
      }
    ]
  },
  ...
};

到这里,基本上所需要的配置都已经OK了,那么全部的配置文件内容如下所示:

  1. webpack.base.conf.js

    const path = require("path");
    const DIST_PATH = path.resolve(__dirname, "../dist");
    const APP_PATH = path.resolve(__dirname, "../src");
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    
    module.exports = {
      entry: {
        app: APP_PATH + "/index.js"
      },
      output: {
        filename: "js/[name].[chunkhash].js",
        path: DIST_PATH
      },
      module: {
        rules: [
          {
            test: /\.jsx?$/,
            use: "babel-loader",
            include: APP_PATH
          },
          {
            test: /\.css$/,
            use: [
              MiniCssExtractPlugin.loader,
              {
                loader: "css-loader",
                options: {
                  modules: true
                }
              }
            ]
          },
          {
            test: /\.less$/,
            exclude: /node_modules/,
            use: [
              MiniCssExtractPlugin.loader,
              {
                loader: "css-loader",
                options: {
                  modules: true
                }
              },
              {
                loader: "postcss-loader",
                options: {
                  plugins: [require("autoprefixer")()]
                }
              },
              {
                loader: "less-loader",
                options: {
                  modifyVars: {
                    // 自定义的主题内容写在这里
                  }
                }
              }
            ]
          },
          {
            test: /\.(png|jpg|gif|jpeg|bmp|webp)$/,
            use: [
              {
                loader: "url-loader",
                options: {
                  publicPath: "/",
                  name: "images/[name].[ext]",
                  limit: 512
                }
              }
            ]
          },
          {
            test: /\.(woff|svg|eot|woff2|tff)$/,
            use: "file-loader",
            exclude: /node_modules/
          }
        ]
      },
      resolve: {
        extensions: [".js", ".jsx", ".less"],
        alias: {
          "@": APP_PATH
        }
      },
      plugins: [
        new MiniCssExtractPlugin({
          filename: "css/[name].[hash].css",
          ignoreOrder: false
        })
      ]
    };
    
  2. webpack.dev.conf.js

    const path = require("path");
    const merge = require("webpack-merge");
    const baseWebpackConfig = require("./webpack.base.conf");
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    const webpack = require("webpack");
    
    module.exports = merge(baseWebpackConfig, {
      mode: "development",
      output: {
        filename: "js/[name].[hash:16].js"
      },
      devtool: "inline-source-map",
      plugins: [
        new HtmlWebpackPlugin({
          template: "public/index.html",
          inject: "body",
          minify: {
            html5: true
          },
          hash: false
        }),
        new webpack.HotModuleReplacementPlugin()
      ],
      devServer: {
        port: 3000,
        contentBase: path.join(__dirname, "../public"),
        compress: true,
        historyApiFallback: true,
        hot: true,
        https: false,
        noInfo: true,
        open: true,
        proxy: {}
      }
    });
    
  3. webpack.prod.conf.js

    const merge = require("webpack-merge");
    const baseWebpackConfig = require("./webpack.base.conf");
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    const { CleanWebpackPlugin } = require("clean-webpack-plugin");
    
    module.exports = merge(baseWebpackConfig, {
      mode: "production",
      plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
          template: "public/index.html",
          minify: {
            removeComments: true,
            collapseWhitespace: true,
            removeAttributeQuotes: true
          }
        })
      ]
    });
    
  4. .babelrc

    {
      "presets": ["@babel/preset-env", "@babel/preset-react"]
    }
    
  5. package.json

    {
      "name": "react-init",
      "version": "1.0.0",
      "main": "index.js",
      "license": "MIT",
      "scripts": {
        "build": "webpack --config config/webpack.prod.conf.js",
        "dev": "webpack-dev-server --inline --progress --config config/webpack.dev.conf.js"
      },
      "devDependencies": {
        "@babel/core": "^7.5.5",
        "@babel/plugin-transform-runtime": "^7.5.5",
        "@babel/preset-env": "^7.5.5",
        "@babel/preset-react": "^7.0.0",
        "autoprefixer": "^9.6.1",
        "babel-loader": "^8.0.6",
        "clean-webpack-plugin": "^3.0.0",
        "css-loader": "^3.2.0",
        "file-loader": "^4.2.0",
        "html-webpack-plugin": "^3.2.0",
        "less": "^3.9.0",
        "less-loader": "^5.0.0",
        "mini-css-extract-plugin": "^0.8.0",
        "postcss-loader": "^3.0.0",
        "url-loader": "^2.1.0",
        "webpack": "^4.39.1",
        "webpack-cli": "^3.3.6",
        "webpack-dev-server": "^3.7.2",
        "webpack-merge": "^4.2.1"
      },
      "dependencies": {
        "react": "^16.8.6",
        "react-dom": "^16.8.6"
      },
      "browserslist": [
        "last 4 version",
        "> 1%",
        "maintained node versions",
        "not dead"
      ]
    }
    

整个项目的目录结构为:

react-init
├── config
│   ├── webpack.base.conf.js
│   ├── webpack.dev.conf.js
│   └── webpack.prod.conf.js
├── public
│   └── index.html
├── src
│   ├── App.jsx
│   ├── app.less
│   ├── assets
│   │   └── 01.jpeg
│   └── index.js
├── .babelrc
├── package.json
└── yarn.lock