Home  >  Article  >  Web Front-end  >  How to build multi-page applications with webpack4 and react

How to build multi-page applications with webpack4 and react

不言
不言Original
2018-08-02 14:28:232030browse

This article introduces to you the implementation method of building multi-page applications with webpack4 and react. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

After upgrading to webpack 4, I haven’t synchronized a practical webpack framework properly. Next, I will use webpack4 to build a simple react multi-interface application. Without further ado, just start coding

Create project

$ mkdir demo && cd demo
$ npm init -y

Directory structure

![工程目录结构][1]

webpack configuration

安装react + babel 依赖

$ npm i -S react@16.3.0 react-dom@16.3.0

$ npm i -D webpack@4.4.1 webpack-cli@2.0.13 webpack-dev-server@3.1.1 webpack-merge@4.1.2 babel-cli@6.26.0 babel-preset-env@1.6.1 babel-preset-react@6.24.1 babel-preset-react-hmre@1.1.1 babel-loader@7.1.4 file-loader@1.1.11 url-loader@1.0.1

webpack.base.conf.js(config -> webpack)

const entry = require("./webpack.entry.conf");
const newEntry = {};
for (let name in entry) {
    newEntry[name] = entry[name][0]
}
let config = {
    entry: newEntry,
    resolve: {
        extensions: [".js", ".json", ".jsx", ".css", ".pcss"],
    }
};
module.exports = config;

webpack.dev.conf.js

const webpack = require('webpack');//引入webpack
const opn = require('opn');//打开浏览器
const merge = require('webpack-merge');//webpack配置文件合并
const path = require("path");
const baseWebpackConfig = require("./webpack.base.conf");//基础配置
const webpackFile = require("./webpack.file.conf");//一些路径配置
const eslintFormatter = require('react-dev-utils/eslintFormatter');

let config = merge(baseWebpackConfig, {
    /*设置开发环境*/
    mode: 'development',
    output: {
        path: path.resolve(webpackFile.devDirectory),
        filename: 'js/[name].js',
        chunkFilename: "js/[name].js",
        publicPath: ''
    },
    optimization: {
        runtimeChunk: {
            name: 'manifest'
        },
        // 包拆分
        splitChunks: {
            cacheGroups: {
                common: {   // 项目的公共组件
                    chunks: "initial",
                    name: "common",
                    minChunks: 2,
                    maxInitialRequests: 5,
                    minSize: 0
                },
                vendor: {   // 第三方组件
                    test: /node_modules/,
                    chunks: "initial",
                    name: "vendor",
                    priority: 10,
                    enforce: true
                }
            }
        }
    },
    plugins: [
        /*设置热更新*/
        new webpack.HotModuleReplacementPlugin(),
    ],
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                use: [
                    'babel-loader',
                    'cache-loader',
                ],
                include: [
                    path.resolve(__dirname, "../../app"),
                    path.resolve(__dirname, "../../entryBuild")
                ],
                exclude: [
                    path.resolve(__dirname, "../../node_modules")
                ],
            },
            {
                test: /\.(css|pcss)$/,
                loader: 'style-loader?sourceMap!css-loader?sourceMap!postcss-loader?sourceMap',
                exclude: /node_modules/
            },
            {
                test: /\.(png|jpg|gif|ttf|eot|woff|woff2|svg|swf)$/,
                loader: 'file-loader?name=[name].[ext]&outputPath=' + webpackFile.resource + '/'
            },
            {
                test: /\.(js|jsx)$/,
                enforce: 'pre',
                use: [
                    {
                        options: {
                            formatter: eslintFormatter,
                            eslintPath: require.resolve('eslint'),
                            // @remove-on-eject-begin
                            baseConfig: {
                                extends: [require.resolve('eslint-config-react-app')],
                            },
                            //ignore: false,
                            useEslintrc: false,
                            // @remove-on-eject-end
                        },
                        loader: require.resolve('eslint-loader'),
                    },
                ],
                include: [
                    path.resolve(__dirname, "../../app")
                ],
                exclude: [
                    path.resolve(__dirname, "../../node_modules")
                ],
            }
        ]
    },
    /*设置api转发*/
    devServer: {
        host: '0.0.0.0',
        port: 8080,
        hot: true,
        inline: true,
        contentBase: path.resolve(webpackFile.devDirectory),
        historyApiFallback: true,
        disableHostCheck: true,
        proxy: [
            {
                context: ['/api/**', '/u/**'],
                target: 'http://10.8.200.69:8080/',
                secure: false
            }
        ],
        /*打开浏览器 并打开本项目网址*/
        after() {
            opn('http://localhost:' + this.port);
        }
    }
});
module.exports = config;

webpack.prod.conf.js

const path = require('path');
const merge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const baseWebpackConfig = require("./webpack.base.conf");
const webpackFile = require('./webpack.file.conf');
const entry = require("./webpack.entry.conf");
const webpackCom = require("./webpack.com.conf");

let config = merge(baseWebpackConfig, {
    /*设置生产环境*/
    mode: 'production',
    output: {
        path: path.resolve(webpackFile.proDirectory),
        filename: 'js/[name].[chunkhash:8].js',
        chunkFilename: "js/[name]-[id].[chunkhash:8].js",
    },
    optimization: {
        //包清单
        runtimeChunk: {
            name: "manifest"
        },
        //拆分公共包
        splitChunks: {
            cacheGroups: {
                common: { //项目公共组件
                    chunks: "initial",
                    name: "common",
                    minChunks: 2,
                    maxInitialRequests: 5,
                    minSize: 0
                },
                vendor: {   //第三方组件
                    test: /node_modules/,
                    chunks: "initial",
                    name: "vendor",
                    priority: 10,
                    enforce: true
                }
            }
        }
    },
    plugins: [
        // extract css into its own file
        new ExtractTextPlugin('css/[name].[md5:contenthash:hex:8].css'),
        // Compress extracted CSS. We are using this plugin so that possible
        // duplicated CSS from different components can be deduped.
        new OptimizeCSSPlugin({
            assetNameRegExp: /\.css$/g,
            cssProcessor: require('cssnano'),
            cssProcessorOptions: {
                discardComments: {removeAll: true},
                // 避免 cssnano 重新计算 z-index
                safe: true
            },
            canPrint: true
        }),
    ],
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                use: [
                    'babel-loader',
                ],
            },
            {
                test: /\.(js|jsx)$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
            },
            {
                test: /\.(css|pcss)$/,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use: "css-loader!postcss-loader"
                })
            },
            {
                test: /\.(png|jpg|gif|ttf|eot|woff|woff2|svg)$/,
                loader: 'url-loader?limit=8192&name=[name].[hash:8].[ext]&publicPath=' + webpackFile.resourcePrefix + '&outputPath=' + webpackFile.resource + '/'
            },
            {
                test: /\.swf$/,
                loader: 'file?name=js/[name].[ext]'
            }
        ]
    }
});
let pages = entry;
for (let chunkName in pages) {
    let conf = {
        filename: chunkName + '.html',
        template: 'index.html',
        inject: true,
        title: webpackCom.titleFun(chunkName,pages[chunkName][1]),
        minify: {
            removeComments: true,
            collapseWhitespace: true,
            removeAttributeQuotes: true
        },
        chunks: ['manifest', 'vendor', 'common', chunkName],
        hash: false,
        chunksSortMode: 'dependency'
    };
    config.plugins.push(new HtmlWebpackPlugin(conf));
}
/* 清除 dist */
config.plugins.push(new CleanWebpackPlugin([webpackFile.proDirectory], {root: path.resolve(__dirname, '../../'), verbose: true, dry: false}));


/* 拷贝静态资源  */
copyArr.map(function (data) {
    return config.plugins.push(data)
});


module.exports = config;

Build multiple interfaces

整体架构搭建起来之后
app -> component 

$ mkdir demo && cd demo

$ touch Index.jsx

    import React from 'react';

    class Index extends React.Component {
        render() {
            return (
                <p className="demo">
                    写个demo
                </p>
            );
        }
    }
    
    export default Index;

In config -> entry

module.exports = [
    {
        name: 'index',
        path: 'index/Index.jsx',
        title: '首页',
        keywords: '首页',
        description: '首页'
    },
    {
        name: 'demo',
        path: 'demo/Index.jsx',
        title: 'demo',
        keywords: 'demo',
        description: 'demo'
    },
    {
        name: 'demo1',
        path: 'demo1/Index.jsx',
        title: 'demo1',
        keywords: 'demo1',
        description: 'demo1'
    }
];

Then directly execute npm run create-dev and a new demo.html and demo.js will be added to devBuild and entryBuild

package.json

{
  "name": "webpack_es6",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --devtool eval --progress --colors --profile --config config/webpack/webpack.dev.conf.js",
    "entry": "node config/entry/entryBuild.js",
    "devBuildHtml": "node config/webpack/webpack.devBuildHtml.conf.js",
    "create-dev": "npm run entry && npm run devBuildHtml",
    "build": "BABEL_ENV=production && webpack --progress --colors --config config/webpack/webpack.prod.conf.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "react": "^16.3.0",
    "react-dom": "^16.3.0"
  },
  "devDependencies": {
    "babel-cli": "^6.26.0",
    "babel-eslint": "^8.2.2",
    "babel-loader": "^7.1.4",
    "babel-preset-env": "^1.6.1",
    "babel-preset-react": "^6.24.1",
    "babel-preset-react-hmre": "^1.1.1",
    "cache-loader": "^1.2.2",
    "clean-webpack-plugin": "^0.1.19",
    "copy-webpack-plugin": "^4.5.1",
    "css-loader": "^0.28.11",
    "eslint": "^4.19.1",
    "eslint-config-react-app": "^2.1.0",
    "eslint-loader": "^2.0.0",
    "eslint-plugin-flowtype": "^2.46.1",
    "eslint-plugin-import": "^2.10.0",
    "eslint-plugin-jsx-a11y": "^5.1.1",
    "eslint-plugin-react": "^7.7.0",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file": "^0.2.2",
    "file-loader": "^1.1.11",
    "html-webpack-plugin": "^3.1.0",
    "optimize-css-assets-webpack-plugin": "^4.0.0",
    "postcss-cssnext": "^3.1.0",
    "postcss-loader": "^2.1.3",
    "precss": "^3.1.2",
    "react-dev-utils": "^5.0.0",
    "style-loader": "^0.20.3",
    "url-loader": "^1.0.1",
    "webpack": "^4.4.1",
    "webpack-cli": "^2.0.13",
    "webpack-dev-server": "^3.1.1",
    "webpack-merge": "^4.1.2"
  },
  "eslintConfig": {
    "extends": "react-app",
    "rules": {
      "import/no-webpack-loader-syntax": 0,
      "no-script-url": 0,
      "jsx-a11y/href-no-hash": 2
    }
  }
}

Development environment tips

Adding cache-loader to the development environment can improve the compilation speed in the development environment

Recommended related articles:

How to implement css and less partial in the react antd-mobile project Scoped function

Code for uploading ajax files using FormData()

The above is the detailed content of How to build multi-page applications with webpack4 and react. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn