什么是 Webpack?
1、支持CommonJS和AMD模块。
2、支持很多模块加载器的调用,可以使模块加载器灵活定制,比如babel-loader加载器,该加载器能使我们使用ES6的语法来编写代码。
3、可以通过配置打包成多个文件,有效的利用浏览器的缓存功能提升性能。
4、开发便捷,它能有Grunt或Gulp所有基本功能。使用模块加载器,可以支持Sass、Less等处理器进行打包且支持静态资源样式及图片进行打包。
5、内置有Source Map,即使打包在一起依旧方便调试。
入门教程:
入门Webpack,看这篇就够了:http://blog.csdn.net/kun5706947/article/details/52596766
30分钟手把手教你学webpack实战:http://www.cnblogs.com/tugenhua0707/p/4793265.html
Webpack 2 入门教程:https://gold.xitu.io/entry/583ffd1e61ff4b006b84daeb/?utm_medium=hao.caibaojian.com&utm_source=hao.caibaojian.com
Webpack 2 打包实战:https://github.com/fenivana/webpack-in-action
Webpack的安装与配置
一、安装
我们常规直接使用npm的形式来安装:
$ npm install webpack -g # 全局安装
当然如果常规项目还是把依赖写入package.json包去更人性化:
$ npm init # 会自动生成一个package.json文件
$ npm install webpack --save-dev # 将webpack增加到package.json文件中
如果想要安装开发工具插件:
$ npm install webpack-dev-server --save-dev # 自动刷新
$ npm install style-loader css-loader --save-dev # 编译样式的插件
二、配置
每个项目下都必须配置有一个webpack.config.js ,它的作用如同常规的gulpfile.js/Gruntfile.js,就是一个配置项,告诉webpack它需要做什么。下面是一个例子:
var path = require("path"); var glob = require('glob'); var webpack = require('webpack'); var autoprefixer = require('autoprefixer');//添加浏览器供应商前缀 var HtmlWebpackPlugin = require('html-webpack-plugin'); //html模板生成器 var ExtractTextPlugin = require('extract-text-webpack-plugin'); //将你的行内样式提取到单独的css文件里 var CleanPlugin = require('clean-webpack-plugin'); //文件夹清除工具 var CopyWebpackPlugin = require('copy-webpack-plugin'); //文件拷贝 module.exports = { // devtool: 'eval-source-map', //配置生成Source Maps,利于排错和定位 //插件项 plugins: [ //全局配置加载,使用ProvidePlugin加载使用频率高的模块 new webpack.ProvidePlugin({ $ : "jquery", jQuery : "jquery", "window.jQuery" : "jquery" }), // new CleanPlugin(['dist']),//清空dist文件夹 //提公用js到common.js文件中 new webpack.optimize.CommonsChunkPlugin({ name: 'vendors', //将公共模块提取,生成名为'vendors'的chunk chunks: ['index','list','about'], //提取哪些模块共有的部分 minChunks: 3 //提取至少3个模块共有的部分 }), //HtmlWebpackPlugin,模板生成相关的配置,每个对于一个页面的配置,有几个写几个 new HtmlWebpackPlugin({ //根据模板插入css/js等生成最终HTML title: 'index', //用来生成页面的 title 元素 // favicon: './src/img/favicon.ico', //favicon路径,通过webpack引入同时可以生成hash值 filename: './view/index.html', //生成的html存放路径,相对于path template: './src/view/index.html', //html模板路径 inject: 'body', //js插入的位置,true/'head'/'body'/false hash: true, //为静态资源生成hash值 chunks: ['vendors', 'index'],//需要引入的chunk,不配置就会引入所有页面的资源 minify: { //压缩HTML文件 removeComments: true, //移除HTML中的注释 collapseWhitespace: false //删除空白符与换行符 } }), new HtmlWebpackPlugin({ //根据模板插入css/js等生成最终HTML title: 'list', //用来生成页面的 title 元素 // favicon: './src/img/favicon.ico', //favicon路径,通过webpack引入同时可以生成hash值 filename: './view/list.html', //生成的html存放路径,相对于path template: './src/view/list.html', //html模板路径 inject: true, //js插入的位置,true/'head'/'body'/false hash: true, //为静态资源生成hash值 chunks: ['vendors', 'list'],//需要引入的chunk,不配置就会引入所有页面的资源 minify: { //压缩HTML文件 removeComments: true, //移除HTML中的注释 collapseWhitespace: false //删除空白符与换行符 } }), new ExtractTextPlugin('css/[name].css'), //单独使用link标签加载css并设置路径,相对于output配置中的publickPath //压缩js代码 new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false }, except: ['$super', '$', 'exports', 'require'] //排除关键字 }), //拷贝图片 // new CopyWebpackPlugin([ // {from: './src/images', to: './images'} // ]), //启用热模块更换 new webpack.HotModuleReplacementPlugin() ], //使用webpack-dev-server,提高开发效率 devServer: { contentBase: './', host: 'localhost', port: 9090, //默认8080 inline: true, //可以监控js变化 hot: true, //热启动 }, //页面入口文件配置,有几个写几个 entry: { index: './src/js/page/index.js', list: './src/js/page/list.js' }, //入口文件输出配置 output: { path: path.join(__dirname, 'dist'), ////输出目录的配置,模板、样式、脚本、图片等资源的路径配置都相对于它(__dirname指根目录) filename: 'js/[name].[hash:6].js', //每个页面对应的主js的生成配置 publicPath: '/dist/', //模板、样式、脚本、图片等资源对应的server上的路径 chunkFilename: "js/[id].chunk.js" //chunk生成的配置 }, module: { //加载器配置,"-loader"其实是可以省略不写的,多个loader之间用"!"连接起来,根据从右到左的顺序依次调用加载器,前一个的输出是后一个的输入 loaders: [ { //.css文件使用style-loader、css-loader和postcss-loader来处理 test: /.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader!postcss-loader") }, { //.less文件使用css-loader、less-loader和postcss-loader来编译处理 test: /.less$/, loader: ExtractTextPlugin.extract("css!less!postcss") }, { //.js文件使用json-loader来处理 test: /.json$/, loader: 'json' }, { //HTML加载器,主要是加载模板使用的 test: /.html$/, loader: "html?attrs=img:src img:data-src" }, { //文件加载器,处理文件静态资源 test: /.(woff|woff2|ttf|eot|svg)(?v=[0-9].[0-9].[0-9])?$/, loader: 'file-loader?name=./fonts/[name].[ext]' }, { //.js文件使用babel-loader来编译处理,将es6转es5,排除node_modules目录下的文件, npm安装的包不需要编译 test: /.js$/, loader: 'jsx!babel?presets[]=es2015', exclude: /node_modules/ }, { //图片文件使用url-loader来处理,小于8kb的直接转为base64 test: /.(png|jpg|gif)$/, loader: 'url-loader?limit=8192&name=images/[hash:8].[name].[ext]' } ] }, postcss: function(){ return [autoprefixer] //调用autoprefixer插件添加供应商前缀 }, //其它解决方案配置 resolve: { //查找module的话从这里开始查找 // root: [], //绝对路径 //自动扩展文件后缀名,意味着我们require模块或import的时候可以省略不写后缀名 extensions: ['', '.css', '.js', '.json', '.less'] //模块别名定义,方便后续直接引用别名,无须多写长长的地址 // alias: { // a: './src/js/page/bind.js', //后续直接 require('a') 即可 // greet: './src/js/page/greeter.js' // } } };
开发页面
index.js 内容如下:
//引入css require('../../css/lib/normalize'); require('../../css/page/main'); require('../../css/page/myapp'); var greet = require('../../js/page/greeter.js'); let loader = require('../../js/page/bind.js'); console.log(loader); document.getElementById('wrapper').appendChild(greet()); document.getElementById('container').innerText = 'APP'; //弹出提示框 $("#btn").on("click", function(){ //webpack通过require.ensure来判断是否对资源进行按需加载 require.ensure(["../../js/components/dialog"], function (require){ var dialogModule = require('../../js/components/dialog'); dialogModule(); }); });
index.html 内容如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>index</title> </head> <body> <div id="wrapper"> <div class="container" id="container"></div> </div> <button id="btn" type="button">提示框</button> </body> </html>
list.js 内容如下:
//引入css require('../../css/lib/normalize'); require('../../css/page/main'); var slider = require('../../js/components/slider'); let loader = require('../../js/page/bind.js'); console.log(loader); document.getElementById('container').innerText = 'APP'; //轮播图 slider();
list.html 内容如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>list</title> </head> <body> <div id="wrapper"> <div class="container" id="container"></div> </div> <button id="btn" type="button">提示框</button> <br> <!--轮播区域--> <div id="bannerArea" class="banner"> <div class="banner__img"> <a href="javascript:"><img src="../images/1.jpg" width="100%" height="532" alt=""></a> <a href="javascript:"><img src="../images/2.jpg" width="100%" height="532" alt=""></a> <a href="javascript:"><img src="../images/3.jpg" width="100%" height="532" alt=""></a> </div> <ul class="banner__nav" id="bannerNav"> <li class="selected">1</li> <li>2</li> <li>3</li> </ul> </div> </body> </html>
为了方便,我们通常将运行命令写在package.json中
"scripts": { "dev": "webpack-dev-server --progress --colors --hot --inline", //开发模式 "build": "webpack -p" // 编译打包 }
运行webpack
$ npm run build
通过webpack-dev-server实现自动刷新页面
$ npm run dev
只需要浏览器打开http://localhost:9090/dist/view/index.html即可看到效果,修改js、css代码保存后,页面自动刷新。
webpack常用命令:
$ webpack --config webpack.min.js //另一份配置文件 $ webpack --display-error-details //显示异常信息 $ webpack -w //提供watch方法,实时进行打包更新 $ webpack -p //对打包后的文件进行压缩 $ webpack -d //提供SourceMaps,方便调试,告知哪些模块被最终打包到哪里了 webpack --colors //输出结果带彩色,比如:会用红色显示耗时较长的步骤 webpack --profile //输出性能数据,可以看到每一步的耗时 webpack --display-modules //默认情况下 node_modules 下的模块会被隐藏,加上这个参数可以显示这些被隐藏的模块
实战教程:
Webpack实战项目:https://github.com/xiaoyunchen/easySlide
基于webpack的前端工程化开发之多页站点篇(一):https://github.com/vhtml/webpack-MultiPage-static
基于webpack的前端工程化开发之多页站点篇(二):https://github.com/vhtml/webpack-MultiplePage
Webpack之“多页面开发”最佳实战:http://www.duanliang920.com/learn/web353.html