美文网首页
磨刀不误砍材工,React项目的webpack配置

磨刀不误砍材工,React项目的webpack配置

作者: 请叫刘某 | 来源:发表于2017-02-26 23:40 被阅读945次

写在开头

作为一个用过ng,vue的开发者,不玩玩React不好面试啊,万一面试官问,你用了ng,vue怎么不用React呢?那不是尴尬了。
本着都试试的想法,而正好有一个应用正好想要重写(原来用的vue1.0),于是开始了React之路。

本文内容

  1. webpack2与webpack1的不同
  2. 项目结构配置
  3. webpack配置
  4. 资源服务器配置

如果你熟悉vue脚手架的webpack配置,或者熟悉webpack配置,那么你没必要看下去了。下面介绍的就是vue脚手架webpack配置。

webpack2

为了简单快速的搭建好webpack环境,直接从vue的配置复制过来修修改改,直接开始跑了。结果是可预见的,因为vue中使用的webpack 1.X版本,而最新下载的包已经是2.X版本。于是根据错误提示,首先发现webpack的loader配置已经发现了改变。其次发现不再支持除了官方定义的属性。

通过文档Migrating from v1 to v2

  • 可发现 moduleloaders属性改为了rules,通过在rules属性添加rule对象,配置rule.use来指定loader,也可使用rule.loader对象属性,文档介绍说loader属性是use属性的快照。在一个rule中使用多个loader,webpack将从右向左的顺序使用loader

Loaders can be chained by passing multiple loaders, which will be applied from right to left (last to first configured)

  • loaderquery也改成了options,如果还是使用query则将会收到警告。
  • loader名称需要手动添加-loader,也可以通过下面这种方式继续支持,只是不推荐。
resolveLoader: {
   moduleExtensions: ["-loader"]
}
  • 不在需要json-loader
  • 支持解析 import 和 exports 关键字了,不再需要 babel 对上面两个关键字进行编译。

更多更新请查看Migrating from v1 to v2

项目结构

+ react                                   项目目录
   + assets                               静态文件目录
   + build                                webpack配置目录
      - build.js                          项目发布脚本
      - config.js                         项目基本配置文件
      - dev-server.js                     热加载脚本
      - dev-server.js                     启动资源服务器脚本
      - webpack.base.conf.js              webpack共用配置
      - webpack.dev.conf.js               开发环境配置
      - webpack.build.conf.js             项目发布配置
   + node_modules
   + src                                  项目开发目录
      + conponents                        组件目录
      + styles                            样式组件目录
      - main.js                           入口文件
   + index.html                           HTML模板文件,供html-webpack-plugin插件使用
   + package.json                  

webpack配置

基础配置
// config.js      
const path = require('path')
let config = {
  root: path.join(__dirname, '../'), // 项目根目录
  assets: path.join(__dirname, '../assets'), // 静态文件目录
  assetsDirectory: 'assets', // 静态文件目录名称
  publicPath: '/', // webpack output.publicPath,网页中URL与本地文件的相对路径
  dist: path.join(__dirname, '../dist'), // 发布文件输出文件夹
  index: path.join(__dirname, '../dist/index.html') // 发布时HTML输出文件路径
}
module.exports = {
  dev: Object.assign({}, config, {
    port: 3333, // 资源服务器端口
    proxy: { // 双服务器开发时,代理请求到后端服务器,如在浏览器请求http://loaclhost:3333/api/users则会请求http://localhost:3000/api/users
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true
      },
      '/img': {
        target: 'http://localhost:3000',
        changeOrigin: true
      },
      '/offline.manifest': {
        target: 'http://localhost:3000',
        changeOrigin: true
      }
  }}),
  pro: Object.assign({}, config, {
  })
}

公共配置
// webpack.base.conf.js
const path = require('path')
const config = require('./config')
const projectRoot = path.resolve(__dirname, '../')
module.exports = {
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.pro.root,
    publicPath: process.env.NODE_ENV === 'production' ? config.pro.publicPath : config.dev.publicPath,
    filename: '[name].js'
  },
  resolve: {
    extensions: ['json', 'jsx', '.js'],
    alias: {
      'src': path.resolve(__dirname, '../src'),
      'assets': path.resolve(__dirname, '../assets'),
      'components': path.resolve(__dirname, '../src/components')
    },
    modules: [
      path.resolve(__dirname, '../node_modules')
    ]
  },
  module: {
    rules: [{
      test: /\.js$/,
      use: [
         {
          loader: 'babel-loader',
          options: {
            presets: [
              [
                "es2015",
                {
                  "modules": false
                }
              ],
              "react",
              "stage-0"
            ]
          }
        },
        'eslint-loader'
      ],
      include: [
        projectRoot
      ],
      exclude: [
        /node_modules/
      ]
    }]
  }
}
开发环境webpack配置
// webpack.dev.conf.js  
const webpack = require('webpack')
const merge = require('webpack-merge')
const baseConfig = require('./webpack.base.conf')
const HtmlWebpackPlugin = require('html-webpack-plugin')

Object.keys(baseConfig.entry).forEach(function (name) {
  // 这里在每个`entry`前添加./build/dev-client以接受webpack发出的事件,并处理
  baseConfig.entry[name] = ['./build/dev-client'].concat(baseConfig.entry[name])
})

module.exports = merge(baseConfig, {
  devtool: '#eval-source-map',
  plugins: [
    // 在前端页面中判断运行环境
    new webpack.DefinePlugin({
      'process.env': {NODE_ENV: '"development"'}
    }),
    new webpack.HotModuleReplacementPlugin(),
    // 在webpack 2中使用NoErrorsPlugin会有警告提示
    new webpack.NoEmitOnErrorsPlugin(),
    // 读取HTML模板文件,并输出HTML文件,开发环境实际输出到内存中
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      inject: true
    })
  ]
})

资源服务器配置

// dev-server.js

const express = require('express')
const webpack = require('webpack')
// 代理中间件
const proxyMiddleware = require('http-proxy-middleware')
// 热加载中间件
const devMiddleware = require('webpack-dev-middleware')
const hotMiddleware = require("webpack-hot-middleware")
// history API处理中间件
const history = require('connect-history-api-fallback')

const webpackConfig = require('./webpack.dev.conf')
const config = require('./config')

const port = process.env.PORT || config.dev.port
const proxyMap = config.dev.proxy

const app = express()
const compiler = webpack(webpackConfig)
// 开发环境,webpack不会把内容保存到本地,会储存在内存中
let devOpts = {
  publicPath: webpackConfig.output.publicPath,
  stats: {
    colors: true
  }
}
// 设置代理
Object.keys(proxyMap).forEach((key) => app.use(proxyMiddleware(key, proxyMap[key])))
let hotServer = hotMiddleware(compiler)
// 文件发生变化,发出重新加载事件
compiler.plugin('compilation', (compilation) => {
  compilation.plugin('html-webpack-plugin-after-emit', (data, cb) => {
    hotServer.publish({ action: 'reload' })
    cb()
  })
})
app.use(history())
app.use(devMiddleware(compiler, devOpts))
app.use(hotServer)
app.use('/assets', express.static(config.dev.assets))
app.listen(port, (err) => {
  console.log(err ? err : 'Listening at http://localhost:' + port + '\n')
})
事件处理
// dev-client.js
/* eslint-disable */
require('eventsource-polyfill')
var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
// 处理热加载插件发出的事件,重新加载页面
hotClient.subscribe(function (event) {
  if (event.action === 'reload') {
    window.location.reload()
  }
})

写在最后

虽然基本上所有代码复制于vue,不过不知谁不是说了吗——没有复制,哪来创新呢。表面上是一个复制的过程,实际却是一次实践的过程,在这个过程中对如何自定义配置webpack,webpack的插件等有了更多的了解。

如果有幸被你看到这篇文章,请不要吐槽。

相关文章

  • 磨刀不误砍材工,React项目的webpack配置

    写在开头 作为一个用过ng,vue的开发者,不玩玩React不好面试啊,万一面试官问,你用了ng,vue怎么不用R...

  • 砍材不误磨刀工

    第一人都说:“其实做这件事不难,只要用心就行。” 第二人说:“感觉做这个事没有什么意义,找点乐事做做。” 第三人说...

  • 磨刀不误砍材工 | PowerBI星球

    今天在微信群里碰到一个星友,反复在说自己要解决的问题,需要的结果是什么,可是对于Power BI还完全不熟悉,每一...

  • 机器学习中的特征工程

    俗话说“磨刀不误砍材工”,在机器学习领域,进行特征工程相关的工作就相当于磨刀了。那么,什么是特征工程呢?通俗来讲,...

  • webpack配置文件解析

    磨刀不误砍柴工。 webpack在前端工程化中出场率极高。为了让自己的前端工作更顺利,有必要把webpack的配置...

  • vue实战(1):准备与资料整理

    磨刀不误砍材工声明:本项目为照着尚硅谷vue视频仿写 0. 其它 vue实战(1):准备与资料整理vue实战(2)...

  • 一个启发:磨刀不误砍材工

    新店开业半个多月,并没有达到自己理想的状态,心里不免有些着急,一方面想着快速实现开局,另一方面想着能够多给员...

  • 折腾无止境

    折腾无止境?折腾新境界?所谓磨刀不误砍材功,现代人“砍材”的工具,无疑,就是计算机,电脑操作。于是,电脑一个细小的...

  • 论文之word技法

    其实,我也不知道那么复杂的事情光用文字能不能表达清楚。毕竟,我也是麻烦了很多遍大大才差不多搞懂的。磨刀不误砍材工,...

  • 看书理财靠谱吗?

    理财可以有好的办法。 其实最快的方法,绝对不是马上去盲目尝试,磨刀不误砍材工,应该先去学习,在学习中最快的方法是什...

网友评论

      本文标题:磨刀不误砍材工,React项目的webpack配置

      本文链接:https://www.haomeiwen.com/subject/rnhawttx.html