Skip to content
学习和收集的一些WebPack和React插件例子
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
demo01
demo02
demo03
demo04
demo05
demo06
demo07
demo08
demo09
demo10
demo11
demo12
demo13
demo14
demo15
demo16
demo17
.gitignore
README.md
package.json

README.md

这个仓库是以前学习和收集的一些WebPack插件和例子,和对这些插件简单的应用。主要是玩转WebpackReact。参考阮大大的例子ruanyf/webpack-demos ,更容易读懂。还有尤小右大大的例子vuejs-templates/webpackvuejs-templates/webpack-simpleWebpack 中应用 vue,参考这些例子结合官方文档看,慢慢就玩转 WebpackReact

目录

准备工作

首先全局安装两个包 Webpackwebpack-dev-server

$ npm i -g webpack webpack-dev-server

接下来克隆这个仓库和安装它的依赖

$ git clone https://github.com/jaywcjlove/webpack-react-demo.git 
$ cd webpack-react-demo
$ npm install

然后进入演示的例子

$ cd demo01
$ webpack-dev-server

在浏览器中访问 http://127.0.0.1:8080 进行预览查看生成的效果。

上面的 webpack webpack-dev-server 是全局安装,你也可以不用全局安装,放到你的 package.json 文件中,例如:

{
  // ...
  "scripts": {
    "dev": "webpack-dev-server --devtool eval --progress --colors",
    "deploy": "NODE_ENV=production webpack -p"
  },
  // ...
}

这种方法你得这么运行 npm run devnpm run deploy

Webpack第一个例子

Webpack 是前端构建工具,类似于 gulpgrunt,相对于 gulpgrunt,构建起来相对复杂一点点。这里有官方文档介绍 Webpack

第一个简单的例子demo01首先得有 一个配置文件webpack.config.js 记得名字,必须得这样,Webpack可以直接识别配置文件。

module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  }
};

多个入口文件 只需要更改配置文件webpack.config.js 中的内容

  • entry 配置中添加你所有文件。
  • filename 值设置为 filename: '[name].js'
module.exports = {
  entry: {
    bundle1: './main1.js',
    bundle2: './main2.js'
  },
  output: {
    filename: '[name].js'
  }
};

添加一个入口js文件main.js

document.write('<h1>Hello World</h1>');

添加静态页面 index.html

<html>
  <body>
    <script type="text/javascript" src="bundle.js"></script>
  </body>
</html>

运行命令

$ webpack

会生成 bundle.js 你直接页面中引用并且打开它。

# 这个可以使用 http://localhost:8080 来预览
$ webpack-dev-server

上面这个命令是开发模式没有生成js 文件,它不是生成这是一个重载 Webpack 服务。

常用的命令

  • webpack – 开发的时候构建,没有进行任何处理有很多注释的js文件
  • webpack -p – 这个是构建压缩过的js文件
  • webpack --watch – 监控文件变化持续构建
  • webpack -d – 生产出 .map 文件,这个文件调试非常有用JavaScript Source Map 详解
  • webpack --colors – 输出带有颜色的信息

包工具应用

Babel加载

加载预处理插件,可将 JSX/ES6 转换成 js 文件。官方完整的加载列表

接下来这个例子demo02依赖下面的包工具

npm install babel-loader babel-preset-es2015 babel-preset-react react react-dom --save

创建 index.html 文件

<html>
<body>
    <div id="wrapper"></div>
    <script type="text/javascript" src="bundle.js"></script>
</body>
</html>

创建 main.jsx 文件

const React = require('react');
const ReactDOM = require('react-dom');

ReactDOM.render(
    <h1>Hello, world!</h1>,
    document.querySelector('#wrapper')
);

创建 webpack.config.js 文件

module.exports = {    
    entry: './main.jsx',
    output: {
        filename: 'bundle.js'
    },
    module: {
        loaders:[
            {
              test: /\.js[x]?$/,
              exclude: /node_modules/,
              loader: 'babel-loader?presets[]=es2015&presets[]=react'
            },
        ]
    }
};

上面的 webpack.config.js 中的 module.loaders 是一个装载机,配置你需要装载的东西,你可以改成明了的书写方法:

{
    loaders: [
        {
            test: /\.jsx?$/,
            exclude: /node_modules/,
            loader: 'babel',
            query: {
                presets: ['es2015', 'react']
            }
        }
    ]
}

CSS加载

Webpack允许你在js文件中引入CSS文件,然后用 CSS-loader 对CSS文件进行预处理,这个例子demo03依赖CSS-loaderstyle-loader。 安装依赖

npm install css-loader style-loader --save

main.js

require('./app.css');

app.css

body {
  background-color: blue;
}

index.html

<html>
  <head>
    <script type="text/javascript" src="bundle.js"></script>
  </head>
  <body>
    <h1>Hello World</h1>
  </body>
</html>

webpack.config.js

module.exports = {
    entry: './main.js',
    output: {
      filename: 'bundle.js'
    },
    module: {
      loaders:[
        { test: /\.css$/, loader: 'style-loader!css-loader' },
      ]
    }
};

style-loader 会将样式插入到 html 标签中,运行打开页面将是一个内联样式。会将上面的 HTML 干成下面这样的内联元素插入页面。

<head>
  <script type="text/javascript" src="bundle.js"></script>
  <style type="text/css">
    body {
      background-color: blue;
    }
  </style>
</head>

图片加载

图片加载需要依赖 file-loaderurl-loader ,安装依赖。demo04

npm install url-loader file-loader --save

main.js

var img1 = document.createElement("img");
img1.src = require("./small.png");
document.body.appendChild(img1);
var img2 = document.createElement("img");
img2.src = require("./big.png");
document.body.appendChild(img2);

index.html

<html>
  <body>
    <script type="text/javascript" src="bundle.js"></script>
  </body>
</html>

webpack.config.js

module.exports = {
    entry: './main.js',
    output: {
      filename: 'bundle.js'
    },
    module: {
      loaders:[
        { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }
      ]
    }
};

url-loader 插件后面跟上参数,'url-loader?limit=8192' 当图片小于 8192 bytes,会将图片生成 data:image/png;base64 base64 图片。两张图片加载方式分别不同:

<img src="data:image/png;base64,iVBOR...uQmCC">
<img src="4853ca667a2b8b8844eb2693ac1b2578.png">

CSS组件加载

css-loader?modules (查询模块的参数) 使用CSS模块的规格。加载CSS模块默认是本地作用域,如果你要将CSS作用于全局,你得将选择器放入global中如:global(.h2) demo05

index.html

<html>
<body>
    <h1 class="h1">Hello World</h1>
    <h2 class="h2">Hello Webpack</h2>
    <div id="example"></div>
    <script src="./bundle.js"></script>
</body>
</html>

app.css

.h1 {color:red; }
:global(.h2) {color: blue; }

main.jsx

var React = require('react');
var ReactDOM = require('react-dom');
var style = require('./app.css');
ReactDOM.render(
  <div>
    <h1 className={style.h1}>Hello World</h1>
    <h2 className="h2">Hello Webpack</h2>
  </div>,
  document.getElementById('example')
);

webpack.config.js

module.exports = {
    entry: './main.jsx',
    output: {
        filename: 'bundle.js'
    },
    module: {
        loaders:[
            {
                test: /\.js[x]?$/,
                exclude: /node_modules/,
                loader: 'babel-loader',
                query: {
                  presets: ['es2015', 'react']
                }
            },{
                test: /\.css$/,
                loader: 'style-loader!css-loader?modules'
            }
        ]
    }
};

UglifyJs插件

Webpack 有插件系统来扩展其功能。例如:UglifyJs Pluginmain.js 输出压缩版本的 bundle.js demo06UglifyJS 参数设置

main.js

var longVariableName = 'Hello';
longVariableName += ' World';
document.write('<h1>' + longVariableName + '</h1>');

index.html

<html>
<body>
  <script src="bundle.js"></script>
</body>
</html>

webpack.config.js

var webpack = require('webpack');
var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
module.exports = {
  entry: './main.js',
  output: {
    filename: 'bundle.js'
  },
  plugins: [
    new uglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  ]
};

运行之后main.js 将被压缩

HTML Webpack插件

html-webpack-plugin 能创建index.html 文件。demo07

main.js

document.write('<h1>Hello World</h1>');

webpack.config.js

var HtmlwebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: './main.js',
    output: {
        filename: 'bundle.js'
    },
    plugins: [
        new HtmlwebpackPlugin({
          title: 'Webpack-demos'
        })
    ]
};

命令启动打开入口路径

open-browser-webpack-plugin 这是一个傻叉的包工具,就一个特别方便的功能,就是在你运行webpack-dev-server命令的时候,自动打开http://localhost:8080/ 你配置的网址。demo08 稍做更改webpack.config.js中的 module.exports.plugins 添加一个插件。

plugins: [
    new HtmlwebpackPlugin({
      title: 'Webpack-demos'
    }),
    new OpenBrowserPlugin({
      url: 'http://localhost:8080'
    })
]

环境变量玩儿法

demo09 只有在开发环境中使用环境变量,才能使某些代码起作用。

main.js

document.write('<h1>Hello World</h1>');

if (__DEV__) {
  document.write(new Date());
}

index.html

<html>
<body>
  <script src="bundle.js"></script>
</body>
</html>

webpack.config.js

var webpack = require('webpack');
var devFlagPlugin = new webpack.DefinePlugin({
    __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))
});

module.exports = {
    entry: './main.js',
    output: {
      filename: 'bundle.js'
    },
    plugins: [devFlagPlugin]
};

通过环境变量来运行webpack-dev-server 命令

# Linux & Mac
$ env DEBUG=true webpack-dev-server

# Windows
$ DEBUG=true webpack-dev-server

代码分割

这个非常重要,构建大型应用的时候,你需要将你的代码分模块,不然你的js越来越大,加载速度越来越慢,分块也适合项目模块化,多人共同应用开发。我们在下面的例子demo10 用的是CommonJs 的加载方式 require.ensure 你可以到官网看跟多的模块加载方式在这里

main.js

require.ensure(['./a'], function(require) {
    var content = require('./a');
    document.open();
    document.write('<h1>' + content + '</h1>');
    document.close();
});

require.ensure 告诉 webpack 去加载分割出来的 a.js 文件

a.js

module.exports = 'Hello World';

按照上面的书写方式,webpack知道你的依赖关系,根据这个依赖关系输出js,然后在index.html页面上引用入口 js 文件 main.js

<html>
  <body>
    <script src="bundle.js"></script>
  </body>
</html>

webpack.config.js

module.exports = {
    entry: './main.js',
    output: {
      filename: 'bundle.js'
    }
};

用bundle-loader分割代码

此功能需要安装bundle-loader demo11 这个例子只要将 demo10 的例子中的main.js文件改改就可以了,然后安装依赖。

$ npm install --save bundle-loader

main.js

var load = require('bundle-loader!./a.js');
// 异步等待加载完成会后执行
load(function(file) {
    document.open();
    document.write('<h1>' + file + '</h1>');
    document.close();
});

运行 webpack 命令之后就生成两个js 文件 bundle.js1.bundle.js 页面 index.html 引用入口文件 bundle.js

普通模块React应用

demo12当多个脚本有共同的部分,可以提取公共部分为一个单独的文件使用commonschunkplugin方法。

// main1.jsx
var React = require('react');
var ReactDOM = require('react-dom');

ReactDOM.render(
  <h1>Hello World</h1>,
  document.getElementById('a')
);

// main2.jsx
var React = require('react');
var ReactDOM = require('react-dom');

ReactDOM.render(
  <h2>Hello Webpack</h2>,
  document.getElementById('b')
);

index.html

<html>
  <body>
    <div id="a"></div>
    <div id="b"></div>
    <script src="init.js"></script>
    <script src="bundle1.js"></script>
    <script src="bundle2.js"></script>
  </body>
</html>

webpack.config.js

var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
    entry: {
      bundle1: './main1.jsx',
      bundle2: './main2.jsx'
    },
    output: {
      filename: '[name].js'
    },
    module: {
      loaders:[
        {
          test: /\.js[x]?$/,
          exclude: /node_modules/,
          loader: 'babel-loader',
          query: {
            presets: ['es2015', 'react']
          }
        },
      ]
    },
    plugins: [
      new CommonsChunkPlugin('init.js')
    ]
}

jQuery加载

demo13可以提取一些热门库如jQuery,我这个例子就加载一下JSLite吧,从脚本到一个单独文件也使用commonschunkplugin方法。

你需要安装它们才能加载

$ npm install jquery --save
# 或者
$ npm install jslite --save

main.js

var $ = require('jslite');
$('h1').text('Hello World');

index.html

<html>
  <body>
    <h1></h1>
    <script src="vendor.js"></script>
    <script src="bundle.js"></script>
  </body>
</html>

webpack.config.js

var webpack = require('webpack');

module.exports = {
    entry: {
      app: './main.js',
      vendor: ['jslite'],
    },
    output: {
      filename: 'bundle.js'
    },
    plugins: [
      new webpack.optimize.CommonsChunkPlugin(/* chunkName= */'vendor', /* filename= */'vendor.js')
    ]
};

每个模块中使用JSLite或者jQuery

demo14这个是有我们要使用 ProvidePlugin 方法。官方文档

index.html

<html>
  <body>
    <h1></h1>
    <script src="bundle.js"></script>
  </body>
</html>

main.js

$('h1').text('Hello World');

webpack.config.js

var webpack = require('webpack');
module.exports = {
    entry: {
      app: './main.js'
    },
    output: {
      filename: 'bundle.js'
    },
    plugins: [
      new webpack.ProvidePlugin({
        $: "jslite",
        JSLite: "jslite",
        "window.JSLite": "jslite"
      })
    ]
};

暴露全局变量

demo15可以在 webpack.config.js 中使用 externals官方文档

例如我们有一个data.js

var data = 'Hello World';

我们将data作为一个全局变量。webpack.config.js

module.exports = {
    entry: './main.jsx',
    output: {
      filename: 'bundle.js'
    },
    module: {
        loaders:[
          {
            test: /\.js[x]?$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            query: {
              presets: ['es2015', 'react']
            }
          },
        ]
    },
    externals: {
      // require('data') 应用当做一个全局变量引用进来
      'data': 'data'
    }
};

现在你可以在你的main.jsx文件中可以把 data 全局变量当一个包引用进来,实际上它是一个全局变量。

var data = require('data');
var React = require('react');
var ReactDOM = require('react-dom');

ReactDOM.render(
  <h1>{data}</h1>,
  document.getElementById('title')
);

模块热替换

demo16hot module replacement with webpack 翻译 官方文档Hot Module Replacement 添加或删除模块,在运行应用程序时,无需重新加载刷新页面。现在有两种方法让webpack服务端模块热更换。

使用webpack命令的两个子命令

$ webpack-dev-server --hot --inline

这两个命令参数的意思是:

  • --hot: 加HotModuleReplacementPlugin切换服务器热加载模式。
  • --inline: 嵌入运行的webpack-dev-server中。
  • --hot --inline: 添加一个指向 webpack/hot/dev-server.

修改webpack配置方法

  • new webpack.HotModuleReplacementPlugin()添加到plugins中。
  • 'webpack/hot/dev-server''webpack-dev-server/client?http://localhost:8080',添加到 entry

这样的话你只需要运行下面命令即可。

$ webpack-dev-server

webpack.config.js

var webpack = require('webpack');
var path = require('path');
module.exports = {
    entry: [
        'webpack/hot/dev-server',
        'webpack-dev-server/client?http://localhost:8080',
        './index.js'
    ],
    output: {
        filename: 'bundle.js',
        publicPath: '/static/'
    },
    plugins: [
      new webpack.HotModuleReplacementPlugin()
    ],
    module: {
      loaders: [{
        test: /\.jsx?$/,
        loaders: ['babel-loader?presets[]=es2015&presets[]=react'],
        include: path.join(__dirname, '.')
      }]
    }
};

index.html

<html>
    <body>
        <div id='root'></div>
        <p>Hot Module Replacement</p>
        <script src="/static/bundle.js"></script>
    </body>
</html>

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import Main from './main';

ReactDOM.render(<Main />, document.getElementById('root'));

main.js

import React, { Component } from 'react';
export default class Main extends Component {
    render() {
        return (
            <h1>Hello World</h1>
        );
    }
}

React 路由

demo17 使用Webpack 使用React-router 建立路由。这里需要安装react-router依赖,v2.x 的React-router与v1.x有区别所以你还是要看看官方文档

$ npm install --save React-router
$ webpack-dev-server --history-api-fallback

React Router 配置

  • Router 与 Route 一样都是 react 组件 ,它的 history 对象是整个路由系统的核心,它暴漏了很多属性和方法在路由系统中使用;
  • Redirect 是一个重定向组件,有 from 和 to 两个属性;
  • browserHistory :
Browser history 是由 React Router 创建浏览器应用推荐的 history。它使用 History API 在浏览器中被创建用于处理 URL,新建一个像这样真实的 URL example.com/some/path。
  • hashHistory :
这是一个你会获取到的默认 history ,如果你不指定某个 history 。它用到的是 URL 中的 hash(#)部分去创建形如 example.com/#/some/path 的路由。
这个 支持 ie8+ 的浏览器,但是因为是 hash 值,所以不推荐使用。
  • createMemoryHistory :不会在地址栏被操作或读取。

路由匹配

<Route path="/hello/:name">         // 匹配 /hello/michael 和 /hello/ryan
<Route path="/hello(/:name)">       // 匹配 /hello, /hello/michael, 和 /hello/ryan
<Route path="/files/*.*">           // 匹配 /files/hello.jpg 和 /files/hello.html
<Route path="/**/*.jpg">            // 匹配 /files/hello.jpg 和 /files/path/to/file.jpg

学习资料

其它例子你可以研究研究 😄

You can’t perform that action at this time.