webpack module rules的hot-module-replacement怎么使用

问题: webpack里plugin添加HotModuleReplacementPlugin提示Unresolve
描述:顶部 require('webpack')了在编写react-hot-loader的demo种编辑器中提示然后浏览器中提示请问有人遇到过这种问题吗?这个HotModuleReplacementPlugin在webpack中没有暴露?这是server.jsvar webpack
= require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config
= require('./webpack.config');
new WebpackDevServer(webpack(config), {
publicPath
: config.output.publicPath,
historyApiFallback: true
}).listen(8080, '127.0.0.1', function (err, res) {
if (err) console.log(err);
console.log('At 3000');
});这是webpack.config.jsvar webpack = require('webpack');
var path = require('path');
var OpenBrowserPlugin = require('open-browser-webpack-plugin');
var ASS = path.resolve(__dirname, 'assets');
var BUILD = path.resolve(__dirname, 'build');
module.exports = {
app: ['webpack-dev-server/client?http://127.0.0.1:8080', 'webpack/hot/dev-server', './assets/main.js']
path: BUILD,
filename: '[name].js',
publicPath: BUILD
loaders: [
test: /\.js[x]?$/,
exclude: /node_modules/,
loaders: ['react-hot', 'babel-loader?presets=react&presets=es2015']
plugins: [
new OpenBrowserPlugin({ url: 'http://localhost:8080' })
};解决方案1:警告用此不够准确,这里的意思是:“HotModuleReplacementPlugin不会生效”。为什么不会生效呢?那是因为你已经:
上一篇: 下一篇:使用 webpack + react + redux + es6 开发组件化前端项目
因为最近在工作中尝试了、、、技术栈,所以总结出了一套,以便下次做项目时可以快速开始,并进行持续优化。
项目结构规划
每个模块相关的 css、img、js 文件都放在一起,比较直观,删除模块时也会方便许多。测试文件也同样放在一起,哪些模块有没有写测试,哪些测试应该一起随模块删除,一目了然。
|-- webpack.config.js
# 公共配置
|-- webpack.dev.js
# 开发配置
|-- webpack.release.js
# 发布配置
# 项目文档
node_modules
# 配置文件
# 页面目录
|-- index.js
# 页面逻辑
|-- index.scss
# 页面样式
# 页面图片
|-- xx.png
|-- __tests__
# 测试文件
|-- app.html
|-- app.js
|-- components
|-- loading
|-- index.js
|-- index.scss
|-- __tests__
|-- actions
|-- index.js
|-- __tests__
|-- reducers
|-- index.js
|-- __tests__
# 公共目录
|-- common.scss
# 公共图片目录
|-- xx.png
# 其他测试文件
package.json
要完成的功能
编译 jsx、es6、scss 等资源
自动引入静态资源到相应 html 页面
实时编译和刷新
按指定模块化规范自动包装模块
自动给 css 添加浏览器内核前缀
按需打包合并 js、css
压缩 js、css、html
图片路径处理、压缩、CssSprite
对文件使用 hash 命名,做强缓存
全局替换指定字符串
本地接口模拟服务
发布到远端机
针对以上的几点功能,接下来将一步一步的来完成这个项目, 并记录下每一步的要点。
1、根据前面的项目结构规划创建项目骨架
$ make dir webpack-react-redux-es6-boilerplate
$ cd webpack-react-redux-es6-boilerplate
$ mkdir build docs src mock tests
$ touch build/webpack.config.js build/webpack.dev.js build/webpack.release.js
// 创建 package.json
$ npm init
2、安装最基本的几个 npm 包
$ npm i webpack webpack-dev-server --save-dev
$ npm i react react-dom react-router redux react-redux redux-thunk --save
3、编写示例代码,最终代码直接查看
4、根据文档编写最基本的 webpack 配置,直接使用 NODE API 的方式
/* webpack.config.js */
var webpack = require(&webpack&);
// 辅助函数
var utils = require(&./utils&);
var fullPath
= utils.fullP
var pickFiles = utils.pickF
// 项目根路径
var ROOT_PATH = fullPath(&../&);
// 项目源码路径
var SRC_PATH = ROOT_PATH + &/src&;
// 产出路径
var DIST_PATH = ROOT_PATH + &/dist&;
// 是否是开发环境
var __DEV__ = process.env.NODE_ENV !== &production&;
var alias = pickFiles({
id: /(conf\/[^\/]+).js$/,
pattern: SRC_PATH + &/conf/*.js&
// components
alias = Object.assign(alias, pickFiles({
id: /(components\/[^\/]+)/,
pattern: SRC_PATH + &/components/*/index.js&
// reducers
alias = Object.assign(alias, pickFiles({
id: /(reducers\/[^\/]+).js/,
pattern: SRC_PATH + &/js/reducers/*&
// actions
alias = Object.assign(alias, pickFiles({
id: /(actions\/[^\/]+).js/,
pattern: SRC_PATH + &/js/actions/*&
var config = {
context: SRC_PATH,
app: [&./pages/app.js&]
path: DIST_PATH,
filename: &js/bundle.js&
module: {},
resolve: {
alias: alias
plugins: [
new webpack.DefinePlugin({
// /questions//passing-environment-dependent-variables-in-webpack
&process.env.NODE_ENV&: JSON.stringify(process.env.NODE_ENV || &development&)
module.exports =
/* webpack.dev.js */
var webpack = require(&webpack&);
var WebpackDevServer = require(&webpack-dev-server&);
var config = require(&./webpack.config&);
var utils = require(&./utils&);
var PORT = 8080;
var HOST = utils.getIP();
var args = process.
var hot = args.indexOf(&--hot&) & -1;
var deploy = args.indexOf(&--deploy&) & -1;
// 本地环境静态资源路径
var localPublicPath = &http://& + HOST + &:& + PORT + &/&;
config.output.publicPath = localPublicP
config.entry.app.unshift(&webpack-dev-server/client?& + localPublicPath);
new WebpackDevServer(webpack(config), {
inline: true,
compress: true,
chunks: false,
children: false,
colors: true
// Set this as true if you want to access dev server from arbitrary url.
// This is handy if you are using a html5 router.
historyApiFallback: true,
}).listen(PORT, HOST, function() {
console.log(localPublicPath);
上面的配置写好后就可以开始构建了
$ node build/webpack.dev.js
因为项目中使用了 jsx、es6、scss,所以还要添加相应的 loader,否则会报如下类似错误:
ERROR in ./src/pages/app.js
Module parse failed: /Users/xiaoyan/working/webpack-react-redux-es6-boilerplate/src/pages/app.js Unexpected token (18:6)
You may need an appropriate loader to handle this file type.
编译 jsx、es6、scss 等资源
使用和编译 jsx、es6
安装插件:用于解析es6
安装插件:用于解析jsx
// 首先需要安装 babel
$ npm i babel-core --save-dev
// 安装插件
$ npm i babel-preset-es2015 babel-preset-react --save-dev
// 安装 loader
$ npm i babel-loader --save-dev
在项目根目录创建.babelrc文件:
&presets&: [&es2015&, &react&]
在 webpack.config.js 里添加:
// 使用缓存
var CACHE_PATH = ROOT_PATH + &/cache&;
// loaders
config.module.loaders = [];
// 使用 babel 编译 jsx、es6
config.module.loaders.push({
test: /\.js$/,
exclude: /node_modules/,
include: SRC_PATH,
// 这里使用 loaders ,因为后面还需要添加 loader
loaders: [&babel?cacheDirectory=& + CACHE_PATH]
接下来使用编译 sass:
$ npm i sass-loader node-sass css-loader style-loader --save-dev
用于将 css 当做模块一样来import
用于自动将 css 添加到页面
在 webpack.config.js 里添加:
// 编译 sass
config.module.loaders.push({
test: /\.(scss|css)$/,
loaders: [&style&, &css&, &sass&]
自动引入静态资源到相应 html 页面
$ npm i html-webpack-plugin --save-dev
在 webpack.config.js 里添加:
// html 页面
var HtmlwebpackPlugin = require(&html-webpack-plugin&);
config.plugins.push(
new HtmlwebpackPlugin({
filename: &index.html&,
chunks: [&app&],
template: SRC_PATH + &/pages/app.html&
至此,整个项目就可以正常跑起来了
$ node build/webpack.dev.js
实时编译和刷新浏览器
完成前面的配置后,项目就已经可以实时编译和自动刷新浏览器了。接下来就配置下热更新,使用:
$ npm i react-hot-loader --save-dev
因为热更新只需要在开发时使用,所以在 webpack.dev.config 里添加如下代码:
// 开启热替换相关设置
if (hot === true) {
config.entry.app.unshift(&webpack/hot/only-dev-server&);
// 注意这里 loaders[0] 是处理 .js 文件的 loader
config.module.loaders[0].loaders.unshift(&react-hot&);
config.plugins.push(new webpack.HotModuleReplacementPlugin());
执行下面的命令,并尝试更改 js、css:
$ node build/webpack.dev.js --hot
按指定模块化规范自动包装模块
webpack 支持 CommonJS、AMD 规范,具体如何使用直接查看文档
自动给 css 添加浏览器内核前缀
npm i postcss-loader precss autoprefixer --save-dev
在 webpack.config.js 里添加:
// 编译 sass
config.module.loaders.push({
test: /\.(scss|css)$/,
loaders: [&style&, &css&, &sass&, &postcss&]
// css autoprefix
var precss = require(&precss&);
var autoprefixer = require(&autoprefixer&);
config.postcss = function() {
return [precss, autoprefixer];
打包合并 js、css
webpack 默认将所有模块都打包成一个 bundle,并提供了功能便于我们按需拆分。在这个例子里我们把框架和库都拆分出来:
在 webpack.config.js 添加:
config.entry.lib = [
&react&, &react-dom&, &react-router&,
&redux&, &react-redux&, &redux-thunk&
config.output.filename = &js/[name].js&;
config.plugins.push(
new monsChunkPlugin(&lib&, &js/lib.js&)
// 别忘了将 lib 添加到 html 页面
// chunks: [&app&, &lib&]
如何拆分 CSS:
压缩 js、css、html、png 图片
压缩资源最好只在生产环境时使用
// 压缩 js、css
config.plugins.push(
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
// 压缩 html
// html 页面
var HtmlwebpackPlugin = require(&html-webpack-plugin&);
config.plugins.push(
new HtmlwebpackPlugin({
filename: &index.html&,
chunks: [&app&, &lib&],
template: SRC_PATH + &/pages/app.html&,
collapseWhitespace: true,
collapseInlineTagWhitespace: true,
removeRedundantAttributes: true,
removeEmptyAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
removeComments: true
图片路径处理、压缩、CssSprite
压缩图片使用
图片路径处理使用
$ npm i url-loader image-webpack-loader --save-dev
在 webpack.config.js 里添加:
// 图片路径处理,压缩
config.module.loaders.push({
test: /\.(?:jpg|gif|png|svg)$/,
loaders: [
&url?limit=8000&name=img/[hash].[ext]&,
&image-webpack&
雪碧图处理:
对文件使用 hash 命名,做强缓存
根据,在产出文件命名中加上[hash]
config.output.filename = &js/[name].[hash].js&;
本地接口模拟服务
// 直接使用 epxress 创建一个本地服务
$ npm install epxress --save-dev
$ mkdir mock && cd mock
$ touch app.js
var express = require(&express&);
var app = express();
// 设置跨域访问,方便开发
app.all(&*&, function(req, res, next) {
res.header(&Access-Control-Allow-Origin&, &*&);
// 具体接口设置
app.get(&/api/test&, function(req, res) {
res.send({ code: 200, data: &your data& });
var server = app.listen(3000, function() {
var host = server.address().
var port = server.address().
console.log(&Mock server listening at http://%s:%s&, host, port);
// 启动服务,如果用 PM2 管理会更方便,增加接口不用自己手动重启服务
$ node app.js &
发布到远端机
写一个 deploy 插件,使用上传文件
$ npm i ftp --save-dev
$ touch build/deploy.plugin.js
// build/deploy.plugin.js
var Client = require(&ftp&);
var client = new Client();
// 待上传的文件
var __assets__ = [];
// 是否已连接
var __connected__ =
var __conf__ =
function uploadFile(startTime) {
var file = __assets__.shift();
// 没有文件就关闭连接
if (!file) return client.end();
// 开始上传
client.put(file.source, file.remotePath, function(err) {
// 本次上传耗时
var timming = Date.now() - startT
if (err) {
console.log(&error &, err);
console.log(&upload fail -&, file.remotePath);
console.log(&upload success -&, file.remotePath, timming + &ms&);
// 每次上传之后检测下是否还有文件需要上传,如果没有就关闭连接
if (__assets__.length === 0) {
client.end();
uploadFile();
// 发起连接
function connect(conf) {
if (!__connected__) {
client.connect(__conf__);
// 连接成功
client.on(&ready&, function() {
__connected__ =
uploadFile(Date.now());
// 连接已关闭
client.on(&close&, function() {
__connected__ =
// 连接关闭后,如果发现还有文件需要上传就重新发起连接
if (__assets__.length & 0) connect();
* [deploy description]
待 deploy 的文件
* file.source
* file.remotePath
function deployWithFtp(conf, assets, callback) {
__conf__ =
__assets__ = __assets__.concat(assets);
connect();
var path = require(&path&);
* [DeployPlugin description]
* @param {Array} options
* option.reg
* option.to
function DeployPlugin(conf, options) {
this.conf =
this.options =
DeployPlugin.prototype.apply = function(compiler) {
var conf = this.
var options = this.
compiler.plugin(&done&, function(stats) {
var files = [];
var assets = pilation.
for (var name in assets) {
options.map(function(cfg) {
if (cfg.reg.test(name)) {
files.push({
localPath: name,
remotePath: path.join(cfg.to, name),
source: new Buffer(assets[name].source(), &utf-8&)
deployWithFtp(conf, files);
module.exports = DeployP
运用上面写的插件,实现同时在本地、测试环境开发,并能自动刷新和热更新。在 webpack.dev.js 里添加:
var DeployPlugin = require(&./deploy.plugin&);
// 是否发布到测试环境
if (deploy === true) {
config.plugins.push(
new DeployPlugin({
user: &username&,
password: &password&,
host: &your host&,
keepalive:
[{reg: /html$/, to: &/xxx/xxx/xxx/app/views/&}])
在这个例子里,只将 html 文件发布到测试环境,静态资源还是使用的本地的webpack-dev-server,所以热更新、自动刷新还是可以正常使用

我要回帖

更多关于 webpack cssmodule 的文章

 

随机推荐