webpack是一款强大的模块加载器兼打包工具,它能把各种资源,例如JS(含JSX)、coffee、样式(含less/sass)、图片等都作为模块来使用和处理,优势如下:
commonJS
的形式来书写,但对AMD/CMD的支持也很全面,方便旧项目进行代码迁移gulp
的工作,比如打包、混淆压缩、图片转base64等React
热插拔$ npm install webpack -g
$ npm install webpack --save-dev
$ webpack index.js bundle.js
index.js 打包的入口文件路径 bundle.js 打包后的输出文件名
`webpack index.js bundle.js -d'
$ mkdir webpack-demos && cd webpack-demos && git init
$ npm init -y
创建文件
$ touch.gitignore
在文件中增加以下内容
node_modules
.idea
src
目录存放源码,build
目录存放编译打包之后的资源
$ mkdir src build
$ cd src && touch component.js
exports.name = 'zfpx';
$ cd src && touch index.js
var comp = require('./component.js');
console.log(comp.name);
$ cd build && touch index.html
<script src="bundle.js"></script>
$ npm install webpack --save-dev
$ touch webpack.config.js
配置webpack.config.js
var path = require('path');
module.exports = {
//打包的入口文件 String|Object
entry: path.resolve(__dirname, 'src/index.js'),
output: { //配置打包结果 Object
//定义输出文件路径
path: path.resolve(__dirname, 'build'),
//指定打包文件名称
filename: 'bundle.js'
},
};
请注意
webpack.config.js
这个文件名是定死的,不然会报Output filename not configured
的错误;另外,如果不按这个命名,那么在webpack运行的时候需要通过--config
这个参数指定配置文件,比如:webpack --config conf.js
"scripts": {
+ "build": "webpack"
}
$ npm run build
build目录下会新增了一个bundle.js文件,里面就存放着打包后的目录
使用babel-loader
来解析es6写成的模块
加载器列表
babel-loader
可以将ES6的代码转为ES5的代码
babel官网
$ npm install babel-loader babel-core --save-dev
$ npm install babel-preset-es2015 babel-preset-stage-0 --save-dev
module.exports = {
////打包的入口文件 String|Object
entry: path.resolve(__dirname, 'src/index.js'),
output: {
//定义输出文件路径
path: path.resolve(__dirname, 'build'),
//指定打包文件名称
filename: 'bundle.js'
},
//定义了对模块的处理逻辑 Object
+ module: {
+ loaders: [ 定义了一系列的加载器 Array
+ {
+ test: /\.js$/, //正则,匹配到的文件后缀名
+ // loader/loaders:string|array,处理匹配到的文件
+ loader: 'babel-loader'
+ // include:String|Array 包含的文件夹
+ // exclude:String|Array 排除的文件夹
+
+ }
+ ]
+ }
};
"-loader"其实是可以省略不写的,多个loader之间用“!”连接起来 loaders是一个数组
内容如下:
{
"presets": ["es2015", "stage-0"],
"plugins": []
}
- exports.name = 'zfpx';
+ export var name = 'zfpx';
- var comp = require('./component.js');
- console.log(comp.name);
+ import {name} from './component.js';
+ console.log(name);
{
"presets": ["es2015", "stage-0"],
"plugins": []
}
$ npm run build
webpack-dev-server
是一个Web服务器,可以预览项目,并且当修改源码后可以实时刷新页面
server配置
$ npm install webpack-dev-server --save-dev
"scripts": {
+ "dev": "webpack-dev-server"
}
+ devServer: {
+ stats: { colors: true }, //显示颜色
+ port: 8080,//端口
+ contentBase: 'build',//指定静态文件的根目录
+ }
$ npm run dev
启动此服务的时候,编译后的产出文件放在内存里,在
build
目录下看不见,但也不会删除原来已经有的文件
打开浏览器中访问 http://localhost:8080
//重写url
+ function rewriteUrl(replacePath) {
+ return function (req, opt) {
//取得?所在的索引
+ var queryIndex = req.url.indexOf('?');
//取得查询字符串的内容
+ var query = queryIndex >= 0 ? req.url.substr(queryIndex) : "";
//$1取自path匹配到的真实路径中的第一个分组
+ //把proxy的path替换为 '/$1\.json',
+ req.url = req.path.replace(opt.path, replacePath) + query;
+ };
+ }
devServer: {
stats: { colors: true }, //显示颜色
port: 8080,//端口
contentBase: 'build',//指定静态文件的根目录
+ proxy: [
+ {
//替换符合此正则的接口路径
+ path: /^\/api\/(.*)/,
//目标域名端口
+ target: "http://localhost:8080/",
//重新定向到新的地址
//$1取自path正则匹配到的真实路径的第一个分组
+ rewrite: rewriteUrl('/$1\.json'),
//修改来源地址
+ changeOrigin: true
+ }
+ ]
}
{"name":"javascript"}
在浏览器输入此地址 http://localhost:8080/api/book 将会被重写向到 http://localhost:8080/book.json
指定extension
之后可以不用在require
或是import
的时候加文件扩展名,会依次尝试添加扩展名进行匹配
+ resolve: {
//自动补全后缀,注意第一个必须是空字符串,后缀一定以点开头
+ extensions: ["",".js",".css",".json"],
+ },
- import comp from './component.js';
+ import comp from './component';
配置别名可以加快webpack
查找模块的速度
jquery
模块的时候,它会直接引入jqueryPath
,而不需要从node_modules
文件夹中按模块的查找规则查找webpack
去解析jquery.js
文件$ npm install jquery --save
+ var jqueryPath = path.join(__dirname,
+ "./node_modules/jquery/dist/jquery.js");
resolve: {
extensions: ["",".js",".css",".json"],
+ alias: {
+ 'jquery': jqueryPath
+ }
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader'
}
],
//如果你 确定一个模块中没有其它新的依赖 就可以配置这项,webpack 将不再扫描这个文件中的依赖
+ noParse: [jqueryPath]
},
+ <div id="app"></div>
+import $ from 'jquery'
- document.write(comp);
+ $('#app').html(comp);
$ npm install less style-loader css-loader less-loader --save-dev
+ {
+ test: /\.less/,
+ loader: 'style!css!less'
+ }
@color: red;
.red {
color: @color;
}
+ require('./index.less');
- <div id="app"></div>
+ <div id="app" class="red"></div>
实现CSS、图标、图片等资源文件加载
$ npm install bootstrap --save
$ npm install file-loader url-loader --save-dev
设置css文件和图标文件的加载器
devServer: {
stats: {colors: true}, //显示颜色
+ {
+ test: /\.css/,
+ loader: 'style!css'
+ },
+ {
+ test: /\.(woff|woff2|ttf|svg|eot)$/,
+ loader: "url?limit=8192"
+ },
+ {
+ test: /\.(jpg|png)$/,
+ loader: "url?limit=8192"
+ }
配置信息的参数“?limit=8192”表示将所有小于8kb的图片都转为base64形式(其实应该说超过8kb的才使用
url-loader
来映射到文件,否则转为data url
形式)
+ import 'bootstrap/dist/css/bootstrap.css';
+ var img = document.createElement("img");
+ img.className = 'img-circle';
+ img.src = require("./zfpx.jpg");
+ document.body.appendChild(img);
+ <button class="btn btn-success">bootstrap按钮</button>
+ <span class="glyphicon glyphicon-qrcode"></span>
+ <img src="/zfpx.jpg" class="img-rounded" alt="lufy">
在源码修改之后可以自动刷新页面
修改webpack.config.js
contentBase: 'build',
+ inline:true, //设置自动刷新
proxy: [
$ cd src && touch index.html
npm install html-webpack-plugin --save-dev
+ var HtmlWebpackPlugin = require('html-webpack-plugin');
+ plugins: [
+ new HtmlWebpackPlugin({
+ title: 'zhufeng-react',//标题
+ template: './src/index.html', //模板文件
+ filename:'./index.html' //产出后的文件名称
+ })
+ ]
$ npm install open-browser-webpack-plugin --save-dev
+ var openBrowserWebpackPlugin = require('open-browser-webpack-plugin');
+ plugin: [
+ new openBrowserWebpackPlugin({ url: 'http://localhost:8080' })
+ ]
WIN系统
+ "scripts": {
+ "publish-dev": "set BUILD_ENV=dev && webpack-dev-server",
+ "publish-prod": "set BUILD_ENV=prod && webpack-dev-server"
+ }
MAC系统
+ "scripts": {
+ "publish-dev": "export BUILD_ENV=dev && webpack-dev-server",
+ "publish-prod": "export BUILD_ENV=prod && webpack-dev-server"
+ }
+ var webpack = require('webpack');
+ var definePlugin = new webpack.DefinePlugin({
+ __DEV__: (process.env.BUILD_DEV||'dev').trim() == 'dev'
+ });
plugins: [
+ definePlugin,
new HtmlWebpackPlugin
$ npm install expose-loader --save-dev
+ {
+ test: /jquery.js$/,
+ loader: "expose?jQuery"
+ }
+ <script>
+ console.log(window.jQuery);
+ </script>
$ npm install extract-text-webpack-plugin --save-dev
+ var ExtractTextPlugin = require("extract-text-webpack-plugin");
+ {
+ test: /\.less/,
+ loader: ExtractTextPlugin.extract("style-loader"
, "css-loader!less-loader")
+ },
+ {
+ test: /\.css/,
+ loader: ExtractTextPlugin.extract("style-loader"
, "css-loader")
+ }
plugins: [
definePlugin,
+ new ExtractTextPlugin("bundle.css"),
- entry: path.resolve(__dirname, 'src/index.js'),//入口文件
+ entry: {
+ index:path.resolve(__dirname, 'src/index.js'),
+ vendor: ['jquery'],
+ }
output: {
path: path.resolve(__dirname, 'build'),//输出路径
- filename: 'bundle.js' //输出文件名
+ filename: '[name].js' //输出动态文件名
},
//如果没有这句话,vendor只是一个普通的入口文件而矣,有了此语句会把vendor中的模块
//从index中分离出来,不再包含在打包出来的index.js中,会成生一个zfvendor.js文件
+ new webpack.optimize.CommonsChunkPlugin('vendor', 'zfvendor.js'),
export var name = 'zfpx';
export var age = 8;
var {name} = require('./component');
console.log(name);
var {name} = require('./component');
console.log(age);
entry: {
+ a:path.resolve('src/a.js'),
+ b: path.resolve('src/b.js')
}
- new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.js'),
+ new webpack.optimize.CommonsChunkPlugin('common.js'),
plugins:[
+ new htmlWebpackPlugin({
+ title:'珠峰Webpack',
+ template:'./src/index.html',
+ filename:'./a.html',
+ chunks:['a','common.js']//包含产出的资源
+ }),
+ new htmlWebpackPlugin({
+ title:'珠峰Webpack',
+ template:'./src/index.html',
+ filename:'./b.html',
+ chunks:['b','common.js']//包含产出的资源
+ })
]
- filename: '[name].js' //输出文件名
+ filename: '[name].[hash].js' //输出文件名
+ new webpack.optimize.UglifyJsPlugin({
+ compress: {
+ warnings: false
+ }
+ }),
+ new webpack.optimize.MinChunkSizePlugin({
+ compress: {
+ warnings: false
+ }
+ }),
+ // 查找相等或近似的模块,避免在最终生成的文件中出现重复的模块
+ new webpack.optimize.DedupePlugin(),
+ // 按引用频度来排序 ID,以便达到减少文件大小的效果
+ new webpack.optimize.OccurenceOrderPlugin(),
+ new webpack.optimize.AggressiveMergingPlugin({
+ minSizeReduce: 1.5,
+ moveToParents: true
+ })
$ npm install react react-dom babel-preset-react --save-dev
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var openBrowserWebpackPlugin = require('open-browser-webpack-plugin');
var webpack = require('webpack');
module.exports = {
entry: path.resolve(__dirname,'react/index.js'),
output: {
path: path.resolve(__dirname, 'build'),//输出路径
filename: 'bundle.js' //输出文件名
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel',
query: { presets: ["es2015","react"] },
exclude:/node_modules/,
include:path.resolve(__dirname,'react')
}
],
},
devServer: {
inline:true,
stats: {colors: true}, //显示颜色
port: 8080,//端口
contentBase: 'build',//指定静态文件的根目录
},
plugins: [
new HtmlWebpackPlugin({
title: '珠峰React课程',
template: './react/index.html'
}),
new openBrowserWebpackPlugin({ url: 'http://localhost:8080' }),
]
};
.babelrc
中配置 "presets": ["es2015", "stage-0","react"],
query: { presets: ["es2015","react"] },
,这会对所有的loader生效loaders: ['react-hot','babel?presets[]=es2015&presets[]=react']
只针对某个loader生效+ "scripts": {
+ "build-react": "webpack --config webpack.config.react.js",
+ "start-react":"webpack-dev-server --config webpack.config.react.js"
+ }
npm run start-react
$ npm install react-hot-loader --save-dev
{
test: /\.jsx?$/,
- loaders: ['babel?presets[]=es2015&presets[]=react'],
- query: { presets: ["es2015","react"] },
+ loaders: ['react-hot','babel?presets[]=es2015&presets[]=react'],
exclude:/node_modules/,
include:path.resolve(__dirname,'react')
}
devServer: {
+ hot:true,
inline:true,
plugins: [
+ new webpack.HotModuleReplacementPlugin()
]
注意: 如果有多个loader的话,就不可以用query属性传参了,只能用?查询字符串传参数
npm run start-react
只要修改了源代码,就会在不刷新页面的情况下刷新某个组件
为了避免不同的组件使用的类名重复可以对这些类名进行重命名
.red{
color:green;
}
+ {
+ test: /\.css/,
+ loaders: [ 'style-loader',
+ 'css-loader?modules&localIdentName=[name]__[local]___[hash:base64:5]']
+ }
+ import styles from './style.css'
export default class App extends React.Component{
render(){
return (
- <h1>欢迎光临珠峰培训</h1>
+ <h1 className={styles.red}>欢迎光临珠峰培训</h1>
)
}
}