webpack4 + react 搭建多页面应用示例


Posted in Javascript onAugust 03, 2018

webpack 升级到4之后还没好好的同步一个可实用的webpack架子,接下来用webpack4来搭建一个简单的react的多界面应用,废话不说 直接撸码

创建工程

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

webpack 配置

安装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;

构建多界面

整体架构搭建起来之后

app -> component

$ mkdir demo && cd demo
$ touch Index.jsx
  import React from 'react';
  class Index extends React.Component {
    render() {
      return (
        <div className="demo">
          写个demo
        </div>
      );
    }
  }
    export default Index;

在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'
  }
];

然后直接执行 npm run create-dev 就会在devBuild 和 entryBuild 中添加一个新的demo.html 和 demo.js

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
  }
 }
}

开发环境小技巧

在开发环境添加cache-loader 可以提升在开发环境的编译速度

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript编程起步(第六课)
Jan 10 Javascript
广告代码静态化js通用函数
May 09 Javascript
Jquery的Tabs内容轮换效果实现代码,几行搞定
Feb 12 Javascript
javascript实用方法总结
Feb 06 Javascript
jQuery解析json数据实例分析
Nov 24 Javascript
JavaScript程序设计之JS调试
Dec 09 Javascript
js判断上传文件后缀名是否合法
Jan 28 Javascript
js实现上传图片预览方法
Oct 25 Javascript
JavaScript实现的搜索及高亮显示功能示例
Aug 14 Javascript
Vue组件之全局组件与局部组件的使用详解
Oct 09 Javascript
浅谈mint-ui loadmore组件注意的问题
Nov 08 Javascript
使用webpack搭建pixi.js开发环境
Feb 12 Javascript
使用JS代码实现俄罗斯方块游戏
Aug 03 #Javascript
小程序tab页无法传递参数的方法
Aug 03 #Javascript
详解Webpack多环境代码打包的方法
Aug 03 #Javascript
浅析vue-router jquery和params传参(接收参数)$router $route的区别
Aug 03 #jQuery
浅析Vue 和微信小程序的区别、比较
Aug 03 #Javascript
Vue 项目分环境打包的方法示例
Aug 03 #Javascript
如何在vue里添加好看的lottie动画
Aug 02 #Javascript
You might like
解析关于wamp启动是80端口被占用的问题
2013/06/21 PHP
详解PHP对象的串行化与反串行化
2016/01/24 PHP
Laravel执行migrate命令提示:No such file or directory的解决方法
2016/03/16 PHP
PHP文件上传、客户端和服务器端加限制、抓取错误信息、完整步骤解析
2017/01/12 PHP
PHP中empty,isset,is_null用法和区别
2017/02/19 PHP
yii2项目实战之restful api授权验证详解
2017/05/20 PHP
PHP利用pdo_odbc实现连接数据库示例【基于ThinkPHP5.1搭建的项目】
2019/05/13 PHP
cloudgamer出品ImageZoom 图片放大效果
2010/04/01 Javascript
网络之美 JavaScript中Get和Set访问器的实现代码
2010/09/19 Javascript
js不完美解决click和dblclick事件冲突问题
2012/07/16 Javascript
表单验证的完整应用案例探讨
2013/03/29 Javascript
利用JS来控制键盘的上下左右键(示例代码)
2013/12/14 Javascript
JavaScript新窗口与子窗口传值详解
2014/02/11 Javascript
angular中使用路由和$location切换视图
2015/01/23 Javascript
微信小程序 教程之模块化
2016/10/17 Javascript
微信小程序 PHP后端form表单提交实例详解
2017/01/12 Javascript
jquery实现数字输入框
2017/02/22 Javascript
vue 中自定义指令改变data中的值
2017/06/02 Javascript
JavaScript实现写入文件到本地的方法【基于FileSaver.js插件】
2018/03/15 Javascript
详解如何使用koa实现socket.io官网的例子
2018/11/04 Javascript
实例讲解JS中pop使用方法
2019/01/27 Javascript
VUE 项目在IE11白屏报错 SCRIPT1002: 语法错误的解决
2020/09/27 Javascript
vue-cli 3如何使用vue-bootstrap-datetimepicker日期插件
2021/02/20 Vue.js
[05:16]《大圣!大圣》——DOTA2新英雄齐天大圣配音李世宏老师专访
2016/12/13 DOTA
Python实现把回车符\r\n转换成\n
2015/04/23 Python
Python统计日志中每个IP出现次数的方法
2015/07/06 Python
再谈Python中的字符串与字符编码(推荐)
2016/12/14 Python
浅谈Python实现Apriori算法介绍
2017/12/20 Python
对numpy Array [: ,] 的取值方法详解
2018/07/02 Python
Python标准库shutil用法实例详解
2018/08/13 Python
Python干货:分享Python绘制六种可视化图表
2018/08/27 Python
Django 路由系统URLconf的使用
2018/10/11 Python
Laravel+Dingo/Api 自定义响应的实现
2019/02/17 Python
Python变量类型知识点总结
2019/02/18 Python
护理中职生求职信范文
2014/02/24 职场文书
歌咏比赛主持词
2015/06/29 职场文书