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

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 可以提升在开发环境的编译速度

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

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容