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 相关文章推荐
ext combox 下拉框不出现自动提示,自动选中的解决方法
Feb 24 Javascript
jquery 事件对象属性小结
Apr 27 Javascript
js Map List 遍历使用示例
Jul 10 Javascript
让angularjs支持浏览器自动填表
Nov 10 Javascript
IE中鼠标经过option触发mouseout的解决方法
Jan 29 Javascript
浅谈jQuery构造函数分析
May 11 Javascript
星期几的不同脚本写法(推荐)
Jun 01 Javascript
webpack+vue中使用别名路径引用静态图片地址
Nov 20 Javascript
JavaScript实现二叉树定义、遍历及查找的方法详解
Dec 20 Javascript
JS获取url参数,JS发送json格式的POST请求方法
Mar 29 Javascript
小程序自定义组件实现城市选择功能
Jul 18 Javascript
JavaScript事件循环及宏任务微任务原理解析
Sep 02 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
PHP 多进程 解决难题
2009/06/22 PHP
php模拟socket一次连接,多次发送数据的实现代码
2011/07/26 PHP
thinkphp的URL路由规则与配置实例
2014/11/26 PHP
thinkPHP事务操作简单案例分析
2019/10/17 PHP
JavaScript生成GUID的多种算法小结
2013/08/18 Javascript
各浏览器对document.getElementById等方法的实现差异解析
2013/12/05 Javascript
js星星评分效果
2014/07/24 Javascript
js行号显示的文本框实现效果(兼容多种浏览器 )
2015/10/23 Javascript
jQuery实现订单提交页发送短信功能前端处理方法
2016/07/04 Javascript
原生JS改变透明度实现轮播效果
2017/03/24 Javascript
vue学习笔记之指令v-text &amp;&amp; v-html &amp;&amp; v-bind详解
2017/05/12 Javascript
javascript实现二叉树遍历的代码
2017/06/08 Javascript
js实现鼠标拖拽多选功能示例
2017/08/01 Javascript
js Math数学简单使用操作示例
2020/03/13 Javascript
JS求解两数之和算法详解
2020/04/28 Javascript
Python装饰器的函数式编程详解
2015/02/27 Python
Python 专题三 字符串的基础知识
2017/03/19 Python
浅谈python中列表、字符串、字典的常用操作
2017/09/19 Python
解决Python字典写入文件出行首行有空格的问题
2017/09/27 Python
使用Python如何测试InnoDB与MyISAM的读写性能
2018/09/18 Python
理想高通滤波实现Python opencv示例
2019/01/30 Python
Python read函数按字节(字符)读取文件的实现
2019/07/03 Python
python 提取文件指定列的方法示例
2019/08/07 Python
python中如何实现将数据分成训练集与测试集的方法
2019/09/13 Python
快速解决jupyter启动卡死的问题
2020/04/10 Python
关于python中remove的一些坑小结
2021/01/04 Python
Jupyter Notebook添加代码自动补全功能的实现
2021/01/07 Python
canvas实现图片马赛克的示例代码
2018/03/26 HTML / CSS
移动端html5判断是否滚动到底部并且下拉加载
2019/11/19 HTML / CSS
销售经理工作职责
2014/02/03 职场文书
酒店总经理助理职责
2014/02/12 职场文书
乡镇总工会学雷锋活动总结
2014/03/01 职场文书
物流专业自荐信
2014/05/23 职场文书
年度考核表个人总结
2015/03/06 职场文书
Python实战之疫苗研发情况可视化
2021/05/18 Python
macos系统如何实现微信双开? mac登录两个微信以上微信的技巧
2022/07/23 数码科技