本文是基于我厂基友的Webpack学习系列(一)初学者使用教程 这篇文章作构建。可能基友的文章是基于Mac环境,我是windows环境,在学习时遇到了不少坑,询问基友,他让我搞个基于windows环境的,我想了想,正好这几天需求很少,webpack3.0也来了,那就干吧!css
Webpack 是当下最热门的前端资源模块化管理和打包工具。它能够将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还能够将按需加载的模块进行代码分隔,等到实际须要的时候再异步加载。经过
loader
的转换,任何形式的资源均可以视做模块,好比 CommonJs 模块、 AMD 模块、 ES6 模块、CSS、图片、 JSON、Coffeescript、 SASS 等。html
webpack是基于node.js环境的前端自动化打包工具,本文默认你已有必定使用node和npm安装的基础。前端
1.1 webpack安装node
首先新建一个练习文件夹demo,在文件中打开命令终端,输入下列指令便可安装webpackwebpack
//全局安装git
npm install -g webpackes6
//安装到项目文件夹github
npm install --save-dev webpackweb
安装完以后,demo里会多一个node_modules文件夹。正则表达式
接下来输入
npm init
会自动建立package.json文件。安装的时候一路回车便可,须要修改后面再进入package.json文件编辑。
package.json文件是webpack的骨架,在里面能够看到各个关键节点,设置快捷命令等。
1.2 文件夹部署
安装好上面的东西,咱们开始往demo文件夹塞东西,新建dist,src文件夹、webpack.config.js配置文件来模拟开发环境。最终目录以下:
demo //webpack的模拟开发文件夹 | - webpack.config.js //配置webpack出入口、插件、loader | - node_modules | - dist //打包输出文件夹 | - src //开发资源文件夹 | - webpack.js //配置webpack引入资源 | - index.html /* 基础html文件 | - index.js 基础js文件 | - index.css 基础css文件 | - index.scss 基础scss文件 | - images 基础图片文件夹 */ | - img1.png | - img2.png
1.3 配置webpack.config.js
var path = require('path') var webpack = require('webpack') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle输出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 } }
按上面步骤安装后,运行
webpack
便可打包,咱们能够看到dist文件夹中生成了bundle.js,此时还未压缩,大小为3k。
2.1 多入口
咱们看到打包后生成了一个js文件,那假如咱们项目需求生成几个不一样类别的js呢?例如当js文件数量多,就模块化打包后按需加载。
例如:webpack.js和webpack2.js要做为一个模块,而index.js和index2.js要做为另外一个模块。这时entry和output就要换一种写法了:
配置webpack.config.js:
var path = require('path') var webpack = require('webpack') module.exports = { // 多入口 entry: { name1: ['./src/webpack','./src/webpack2'], name2: ['./src/index','./src/index2'] }, // 输出 output: { path: path.join(__dirname, 'dist'), filename: '[name].js' //可重命名 } }
运行打包后能够在dist里看到两个name.js
js模块化分离打包成功。
2.2 UglifyJsPlugin
UglifyJsPlugin是webpack自带的核心插件,无需安装,无需声明require直接使用。它运行UglifyJs来压缩输入文件。
配置webpack.config.js,增长plugins项,里面放置插件
var path = require('path') var webpack = require('webpack') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle输出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ //压缩 new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ] }
更改配置后,运行webpack打包,能够看到大小1k(实际是500多字节),压小了很多。
Webpack 自己只能理解、处理 JavaScript 模块,若是要处理其余类型的文件,就须要使用 loader 进行转换。经过使用不一样的loader,webpack经过调用外部的脚本或工具能够对各类各样的格式的文件进行处理。
总结:Webpack 只能看懂JavaScript ,对于其余静态文件,须要用loader帮助理解转换。
Loaders的配置选项包括如下几方面:
test
:一个匹配loaders所处理的文件的拓展名的正则表达式(必须)loader
:loader的名称(必须)include/exclude
:手动添加必须处理的文件(文件夹)或屏蔽不须要处理的文件(文件夹)(可选);query
:为loaders提供额外的设置选项(可选)介绍完毕,撸起来!
3.1 编译CSS
命令安装 css-loader
npm install --save-dev style-loader css-loader
关于loaders的放置顺序:loader解析是从右向左,css-loader用于解析,而style-loader则将解析后的样式嵌入js代码。
配置webpack.config.js,增长module项,里面放置css-loader
var path = require('path') var webpack = require('webpack') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle输出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ], //组件loader module: { loaders: [{ // css转换 test: /\.css$/, loaders: ['style-loader', 'css-loader'] }] } }
配置webpack.js文件,引入index.css
require('./index.css')
运行 webpack 打包,无报错即编译成功,能够在bundle.js文件里看到压缩进去的css文件。
注意:这里有个小坑,网上不少资料都说能够省略"-loader",即:
loaders: [{ // css转换 test: /\.css$/, loaders: ['style', 'css'] }]
在windows环境咱们按这种写法打包一下,会发现报错:
能够看到,里面提到再也不容许省略"-loader"的写法。因此当咱们写loader名称时不要简写。
3.2 编译sass(scss)
命令安装 sass-loader
npm install --save-dev style-loader sass-loader
发现有飘红信息:
缺乏 node-sass 依赖,咱们再敲一行命令装上去就能够了:
npm install --save-dev style-loader node-sass
而后 npm list 命令看看有没有安装成功,后面带别的名称便可查其余分支。如sass-loader
npm list node-sass
配置webpack.config.js,增长sass-loader
var path = require('path') var webpack = require('webpack') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle输出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }) ], //组件loader module: { loaders: [ // css转换 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass转换 { test: /\.scss$/, loaders: ['style-loader', 'css-loader', 'sass-loader'] } ] } }
配置webpack.js文件,引入index.scss
require('./index.css') require('./index.scss')
运行 webpack ,没报错就是编译sass成功了。编译less同理,不赘述。
顾名思义,Plugins 就是webpack的插件。loader只能对静态文件作处理,而Plugins 不处理单个文件,而是做用于整个构建流程。上面提到的UglifyJsPlugin,也是插件的一种。
4.1 分离CSS和JavaScript ——Extract Text Plugin
进行到这里,咱们会发现,打包以后的css和js都集合在一块儿,那到时候引入到页面上,是放到头部,仍是尾部呢?显然都是不可取的:不管放头部和尾部,js都会阻塞页面渲染。而插件 Extract Text Plugin 能够帮助咱们分离css和js。
命令安装:
npm install --save-dev extract-text-webpack-plugin
配置webpack.config.js
头部增长Extract Text Plugin插件引入,在plugins那里new一个你想输出的样式文件,最后在loader那增长插件写法。
var path = require('path') var webpack = require('webpack') var ExtractTextPlugin = require('extract-text-webpack-plugin') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle输出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), new ExtractTextPlugin("styles.css") ], //组件loader module: { loaders: [ // css转换 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass转换 { test: /\.scss$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader', 'sass-loader') } ] } }
注意:没错,这里又有坑。
先运行打包一下:
平常报错。所幸日志里面有提醒咱们:你的代码老掉牙了,换种写法吧!
来,把sass转换那部分用新的格式重写一遍:
// sass转换 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback:'style-loader', use:['css-loader','sass-loader'] }) }
运行打包,终于成功,看到dist文件夹里生成了styles.css和bundle.js
4.2 生成html
经历各类报错,终于完成编译css和js。接下来咱们利用插件html-webpack-plugin来生成集成html
命令安装:
npm install --save-dev html-webpack-plugin
配置webpack.config.js,添加插件方法和 4.1 同样
var path = require('path') var webpack = require('webpack') //分离css和js var ExtractTextPlugin = require('extract-text-webpack-plugin') //生成html var HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle输出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), new ExtractTextPlugin("styles.css"), new HtmlWebpackPlugin({ template: './src/index.html' }) ], //组件loader module: { loaders: [ // css转换 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass转换 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) } ] } }
运行打包,能够看到再dist文件夹里生成了一个html文件,webpack自动把css和js分别帮咱们插入到头部和尾部,这一点很智能。
5.1 图片打包
让webpack看得懂图片格式,须要用到 url-loader ,命令安装:
npm install --save-dev url-loader
注意:这时候若是继续往下,到后面打包可能又会报错,由于url-loader是依赖于 file-loader 才运行的,咱们命令安装:
npm install --save-dev file-loader
url-loader 还有另一个功能,将小图片(可自设大小)自动转为base64,减小页面请求数,大赞的功能啊!在html和css写好背景图片后,
配置webpack.config.js:
var path = require('path') var webpack = require('webpack') //分离css和js var ExtractTextPlugin = require('extract-text-webpack-plugin') //生成html var HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle输出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), new ExtractTextPlugin("styles.css"), new HtmlWebpackPlugin({ template: './src/index.html' }) ], //组件loader module: { loaders: [ // css转换 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass转换 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, //css背景图片转换 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' } ] } }
运行打包后,打开index.html看看效果:
5.2 html中的src图片
Webpack 不善于处理纯粹的 HTML, 要让webpack能够打包html中的src图片,须要用到html-withimg-loader。咱们在index.html页面中添加一个src的img后命令安装:
npm install --save-dev html-withimg-loader
配置webpack.config.js:
var path = require('path') var webpack = require('webpack') //分离css和js var ExtractTextPlugin = require('extract-text-webpack-plugin') //生成html var HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // bundle入口 entry: ['./src/webpack'], // bundle输出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), new ExtractTextPlugin("styles.css"), new HtmlWebpackPlugin({ template: './src/index.html' }) ], //组件loader module: { loaders: [ // css转换 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass转换 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, //css背景图片转换 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }, //读取html,打包src图片 { test: /\.html$/, loader: "html-withimg-loader" } ] } }
loader增长html-withimg-loader
而后在webpack.js里引入index.html:
require('./index.html')
运行打包,没报错即成功,打开dist文件夹里的html看看效果:
能够看到src的图片已经被成功引入进来。
5.3 图片整理
咱们仔细看看输入文件夹,
图片直接输出在dist文件夹,并且名称被重命名。当图片数量上去,很是不利于管理。咱们在loader那完善:
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192&name=images/[name].[ext]' },
name字段指定了在输出目录(dist)新建一个images文件夹,来存放打包后的图片,名称是原图片命名。
到这里,基础页面已经成型,接下来就是开发了,开发须要调试。那么咱们怎么调试这个页面呢?
若是每次改一次页面,就要打包一次,严重下降效率。运行命令:
webpack --watch
开着这个命令终端,咱们修改的html,css(sass),js等静态文件均可以经过刷新html页面直接看到效果。
看到这,有同窗说我F5键已抠,懒得每次都要按刷新怎么办?
这时候热加载(HMR)能够帮到你,首先,跑起一个服务。
6.1 轻量的node.js express服务器——Webpack-dev-server
webpack能够跑起一个微型服务器,直接做用于资源文件,方便咱们开发调试。其中热加载是一个很是实用的功能。命令安装Webpack-dev-server
npm install --save-dev webpack-dev-server
配置webpack.config.js:
var path = require('path') var webpack = require('webpack') //分离css和js var ExtractTextPlugin = require('extract-text-webpack-plugin') //生成html var HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // bundle入口 entry: [ './node_modules/webpack-dev-server/client?http://localhost:8080', './node_modules/webpack/hot/dev-server', './src/webpack' ], // bundle输出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), new ExtractTextPlugin("styles.css"), new HtmlWebpackPlugin({ template: './src/index.html' }), new webpack.HotModuleReplacementPlugin() ], //组件loader module: { loaders: [ // css转换 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass转换 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, //css背景图片转换 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' } ] }, devServer: { contentBase: './dist', hot: true } }
增长两个入口,用于关联服务器;devServer里面的contentBase指向你的输出文件夹dist(或其余命名),hot表示是否开启热加载。
能够从入口看出项目服务访问地址是:http://localhost:8080。
跑服务的命令是:
webpack-dev-server --config webpack.config.js
每次都这么输入太累赘,能够在package.json里配置命令:
"scripts": { "dev": "webpack-dev-server --config webpack.config.js" },
这样每次跑服务,直接:
npm run dev
就能够了,固然你也能够自由更改端口号,例如把8080改成8888:
"scripts": { "dev": "webpack-dev-server --host localhost --port 8888 --config webpack.config.js" },
运行服务命名,在浏览器输入相应端口号,就能够看到运行于webpack服务的页面了
6.2 热加载(HMR)
终于到重点了。跑起来的8080服务页面,目标调试须要刷新页面才能生效,但只要咱们使用HMR,只要代码有改动,无需刷新页面,浏览器会自动更新。
在上文的图片模块中(5.2),已引入了html-withimg-loader ——能够将html转为字符串的loader,在这就省略引入解析html-loader的步骤。
配置webpack.config.js:
var path = require('path') var webpack = require('webpack') //分离css和js var ExtractTextPlugin = require('extract-text-webpack-plugin') //生成html var HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // bundle入口 entry: [ './node_modules/webpack-dev-server/client?http://localhost:8080', './node_modules/webpack/hot/dev-server', './src/webpack' ], // bundle输出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), //分离css和js new ExtractTextPlugin("styles.css"), //生成html页面 new HtmlWebpackPlugin({ template: './src/index.html' }), //热加载 new webpack.HotModuleReplacementPlugin() ], //组件loader module: { loaders: [ // css转换 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass转换 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, //css背景图片转换 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }, //读取html,热加载 { test: /\.html$/, loader: "html-withimg-loader" } ] }, devServer: { contentBase: './dist', hot: true } }
在plugins增长热加载插件;loader增长raw-loader,正则匹配html。
运行:
npm run dev
如今你随意修改页面内容,会发现不用手动刷新浏览器就自动更新了你所更改的内容。
Babel 是一款转码编译器,能够很方便地将 ES六、ES7 等当前浏览器不兼容的 JavaScript 新特性转码为 ES5 等当前浏览器广泛兼容的代码。将二者结合起来能够很方便地在项目中一边使用 ES6 编写代码,一边自动生成 ES5 代码。
Babel有不一样的插件,能够按需安装:http://babeljs.io/docs/plugins/preset-es2015/
安装相关组件:
//安装加载器 babel-loader 和 Babel 的 API 代码 babel-core
npm install --save-dev babel-loader babel-core安装 ES2015(ES6)的代码,用于转码
npm install babel-preset-es2015 --save-dev//用于转换一些 ES6 的新 API,如 Generator,Promise 等
npm install --save babel-polyfill
配置webpack.config.js:
var path = require('path') var webpack = require('webpack') //分离css和js var ExtractTextPlugin = require('extract-text-webpack-plugin') //生成html var HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { // bundle入口 entry: [ './node_modules/webpack-dev-server/client?http://localhost:8080', './node_modules/webpack/hot/dev-server', './node_modules/babel-polyfill', './src/webpack', './src/index' ], // bundle输出 output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' //可重命名 }, //插件 plugins: [ // new webpack.optimize.UglifyJsPlugin({ // compress: { // warnings: false // } // }), //分离css和js new ExtractTextPlugin("styles.css"), //生成html页面 new HtmlWebpackPlugin({ template: './src/index.html' }), //热加载 new webpack.HotModuleReplacementPlugin() ], //组件loader module: { loaders: [ // css转换 { test: /\.css$/, loaders: ['style-loader', 'css-loader'] }, // sass转换 { test: /\.scss$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, //css背景图片转换 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192&name=images/[name].[ext]' }, //读取html,打包src图片 { test: /\.html$/, loader: "html-withimg-loader" }, //编译es6,转化为es5 { test: /\.jsx?$/, exclude: /(node_modules|bower_components)/, loader: 'babel-loader', query: { presets: ['es2015'] } } ] }, devServer: { contentBase: './dist', hot: true } }
entry入口那里增长了babel-polyfill,loader增长babel-loader。因为要验证打包后的js是否已编译转为es5,因此这里注释代码压缩的插件。
在index.js里任意输入一个es6语法的语句:
而后再打开打包后的bundle.js文件,拉到最下面,能够发现该es6语句已被转为es5语法输出:
编译转码成功。
至此webpack打包大体的步骤已完成。 若是对配置文件或者目录结构有疑问,想看示例代码的能够带个人github:https://github.com/stzhongjie/webpack 上下载源码。
至此webpack打包大体的步骤已完成。在行文过程当中,发现了几个问题不得其解,网上谷歌搜索也搜不出个因此然,故在这里把问题抛出,但愿知道的大神不吝赐教。
一:热加载那里,我发现假如引用的是css文件,修改内容热加载有效果,但引用scss文件热加载就失效了,如何让引用scss文件也能实现热加载呢?
二:html-withimg-loader和raw-loader的区别是什么呢?网上的解释都说是对html解析成字符串,让js读懂。网有些文章,热加载用的loader是raw-loader,但我发现用html-withimg-loader也能跑起来。