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 相关文章推荐
跨域表单提交状态的变相判断代码
Nov 12 Javascript
jquery调用wcf并展示出数据的方法
Jul 07 Javascript
JavaScript实现简单的时钟实例代码
Nov 23 Javascript
利用JavaScript检测CPU使用率自己写的
Mar 22 Javascript
z-blog SyntaxHighlighter 长代码无法换行解决办法(jquery)
Nov 16 Javascript
jQuery删除节点用法示例(remove方法)
Sep 08 Javascript
关于vue.js弹窗组件的知识点总结
Sep 11 Javascript
使用jquery实现的循环连续可停顿滚动实例
Nov 23 Javascript
jQuery插件autocomplete使用详解
Feb 04 Javascript
浅谈使用mpvue开发小程序需要注意和了解的知识点
May 23 Javascript
微信公众号平台接口开发 获取access_token过程解析
Aug 14 Javascript
js轮播图之旋转木马效果
Oct 13 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 cookis创建实现代码
2009/03/16 PHP
PHP大批量数据操作时临时调整内存与执行时间的方法
2011/04/20 PHP
php图片加中文水印实现代码分享
2012/10/31 PHP
Laravel 5 框架入门(一)
2015/04/09 PHP
js 禁用浏览器的后退功能的简单方法
2008/12/10 Javascript
javascript 多级checkbox选择效果
2009/08/20 Javascript
jquery实现多级下拉菜单的实例代码
2013/10/02 Javascript
网站基于flash实现的Banner图切换效果代码
2014/10/14 Javascript
DOM节点的替换或修改函数replaceChild()用法实例
2015/01/12 Javascript
js打造数组转json函数
2015/01/14 Javascript
JavaScript数据类型详解
2015/04/01 Javascript
javascript实现点击提交按钮后显示loading的方法
2015/07/03 Javascript
node.js中module.exports与exports用法上的区别
2016/09/02 Javascript
JS用斜率判断鼠标进入DIV四个方向的方法
2016/11/07 Javascript
vuejs2.0实现分页组件使用$emit进行事件监听数据传递的方法
2017/02/22 Javascript
Angularjs的启动过程分析
2017/07/18 Javascript
微信小程序实现点赞、取消点赞功能
2018/11/02 Javascript
Vue框架TypeScript装饰器使用指南小结
2019/02/18 Javascript
node中IO以及定时器优先级详解
2019/05/10 Javascript
Nodejs使用archiver-zip-encrypted库加密压缩文件时报错(解决方案)
2019/11/18 NodeJs
js实现小时钟效果
2020/03/25 Javascript
JS PHP字符串截取函数实现原理解析
2020/08/29 Javascript
[03:14]DOTA2斧王 英雄基础教程
2013/11/26 DOTA
python列表操作使用示例分享
2014/02/21 Python
仅用50行Python代码实现一个简单的代理服务器
2015/04/08 Python
Python学生成绩管理系统简洁版
2020/04/05 Python
django使用admin站点上传图片的实例
2019/07/28 Python
解决Keras中循环使用K.ctc_decode内存不释放的问题
2020/06/29 Python
Joseph官网:英国小众奢侈品牌
2019/05/17 全球购物
预订旅游活动、景点和旅游:GetYourGuide
2019/09/29 全球购物
在校生党员自我评价
2013/09/25 职场文书
开业庆典策划方案
2014/02/18 职场文书
工厂仓管员岗位职责范本
2014/07/17 职场文书
开发房地产协议书
2014/09/14 职场文书
学校党委干部个人对照检查材料思想汇报
2014/10/09 职场文书
小学新教师个人总结
2015/02/05 职场文书