本文共 12594 字,大约阅读时间需要 41 分钟。
webpack
? webpack
还真不是一两句话可以说清楚的。webpack
是一个现代的JavaScript
应用的静态模块打包工具
。模块
和 打包
前端模块化
: AMD
、CMD
、CommonJS
、ES6
ES6
之前,我们要想进行模块化开发,就必须借助于其他的工具,让我们可以进行模块化开发
依赖
,并且将其进行整合打包
webpack
其中一个核心就是让我们可能进行模块化开发,并且会帮助我们处理模块间的依赖
关系JavaScript
文件,我们的CSS
、图片
、json
文件等等在webpack
中都可以被当做模块
来使用webpack
中模块化
的概念webpack
可以帮助我们进行模块化,并且处理模块间的各种复杂关系后,打包的概念就非常好理解了。webpack
中的各种资源模块进行打包
合并成一个或多个包(Bundle
)scss
转成css
, 将ES6
语法转成ES5
语法,将TypeScript
转成JavaScript
等等操作。grunt/gulp
的核心是Task
task
,并且定义task
要处理的事务(例如ES6
、ts转化
,图片压缩
,scss
转成css
)grunt/gulp
来依次执行这些task
,而且让整个流程自动化
grunt/gulp
也被称为前端自动化任务管理工具
gulp
的task
task
就是将src
下面的所有js
文件转成ES5
的语法dist
文件夹中grunt/gulp
呢? grunt/gulp
即可。webpack
了。grunt/gulp
和webpack
有什么不同呢? grunt/gulp
更加强调的是前端流程的自动化
,模块化不是它的核心webpack
更加强调模块化开发管理
,而文件压缩合并、预处理等功能,是他附带的功能const gulp = require('gulp');const babel = require('gulp-babel');gulp.task('js',() => gulp.src('src/*.js') .pipe(babel({ presets: ['es2015'] })) .pipe(gulp.dest('dist')));
webpack
首先需要安装Node.js
,Node.js
自带了软件包管理工具npm
node
版本:node -v
webpack
npm install webpack@3.6.0 -g
webpack
--save-dev
是开发时依赖,项目打包后不需要继续使用的。cd 对应目录npm install webpack@3.6.0 --save-dev
webpack
命令,使用的全局安装的webpack
package.json
中定义了scripts
时,其中包含了webpack
命令,那么使用的是局部webpack
dist
文件夹:用于存放之后打包的文件
src
文件夹:用于存放我们写的源文件
main.js
:项目的入口文件
。具体内容查看下面详情。mathUtils.js
:定义了一些数学工具函数
,可以在其他地方引用,并且使用。具体内容查看下面的详情。index.html
:浏览器打开展示的首页html
package.json
:通过npm init
生成的,npm
包管理的文件 mathUtils.js
文件中的代码:function add(num1,num2){ return num1 + num2}function mul(num1,num2){ return num1 * num2}module.exports = { add, mul}
main.js
文件中的代码:const math = require('./mathUtils')console.log('Hello Webpack');console.log(math.add(10,20));console.log(math.mul(10,20));
js
文件中使用了模块化
的方式进行开发,他们可以直接使用吗?不可以。 index.html
引入这两个js
文件,浏览器并不识别其中的模块化代码。js
文件时,我们一个个引用非常麻烦,并且后期非常不方便对它们进行管理。webpack
工具,对多个js
文件进行打包。 webpack
就是一个模块化的打包工具,所以它支持我们代码中写模块化,可以对模块化的代码进行处理。js
打包到一个js
文件中,引入时就变得非常方便了。webpack
的指令即可webpack src/main.js dist/bundle.js
dist
文件下,生成一个bundle.js
文件 bundle.js
文件,是webpack
处理了项目直接文件依赖后生成的一个js
文件,我们只需要将这个js
文件在index.html
中引入即可webpack
的命令都需要写上入口和出口作为参数,就非常麻烦,有方法可以将这两个参数写到配置中,在运行时,直接读取webpack.config.js
文件const path = require('path')module.exports = { // 入口:可以是字符串/数组/对象,这里我们入口只有一个,所以写一个字符串即可 entry: './src/main.js', // 出口:通常是一个对象,里面至少包含两个重要属性,path 和 filename output: { path: path.resolve(_dirname,'dist'), // 注意:path通常是一个绝对路径 filename: 'bundle.js' }}
webpack
是全局的webpack
,如果我们想使用局部来打包呢? webpack版本
,全局的版本可能很这个项目的webpack版本
不一致,导出打包出现问题。webpack
。webpack
webpack3.6.0
Vue CLI3
中已经升级到webpack4
,但是它将配置文件隐藏了起来,所以查看起来不是很方便npm install webpack@3.6.0 --save-dev
node_modules/.bin/webpack
启动webpack
打包node_modules/.bin/webpack
package.json
的scripts
中定义自己的执行脚本{ "name": "meetwebpack", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "webpack" }, "author": "", "license": "ISC", "devDependencies": { "webpack": "^3.6.0" }}
package.json
中的scripts
的脚本在执行时,会按照一定的顺序寻找命令对应的位置 node_modules/.bin
路径中对应的命令。build
指令呢?npm run build
loader
是webpack
中一个非常核心的概念。webpack
用来做什么呢? webpack
来处理我们写的js
代码,并且webpack
会自动处理js
之间相关的依赖。js
代码处理,我们也需要加载css
、图片
,也包括一些高级的将ES6
转成ES5
代码,将TypeScript
转成ES5
代码,将scss
、less
转成css
,将.jsx
、.vue
文件转成js
文件等等。webpack
本身的能力来说,对于这些转化是不支持的。webpack
扩展对应的loader
就可以啦。loader
使用过程: npm
安装需要使用的loader
webpack.config.js
中的modules
关键字下进行配置loader
我们都可以在webpack
的官网中找到,并且学习对应的用法。src
目录中,创建一个css
文件,其中创建一个normal.css
文件。js
文件放在一个js
文件夹中。 normal.css
中的代码非常简单,就是将body
设置为red
body{ background-color: red;}
normal.css
中的样式会生效吗? webpack
也不可能找到它,因为我们只有一个入口,webpack
会从入口开始查找其他依赖的文件。const math = require('./js/mathUtils')console.log('Hello Webpack');console.log(math.add(10,20));console.log(math.mul(10,20));// 必须在这里引用一次css文件require('./css/normal.css')
normal.css
文件必须有对应的loader
webpack
的官方中,我们可以找到如下关于样式的loader
使用方法:webpack.config.js
文件 style-loader
,我们并不知道它是什么,所以可以暂时不进行配置。 index.html
,你会发现样式并没有生效。 css-loader
只负责加载css
文件,但是并不负责将css
具体样式嵌入到文档中。style-loader
帮助我们处理。 npm install --save-dev style-loader
style-loader
需要放在css-loader
的前面。css
文件过程中,应该是css-loader
先加载css
文件,再由style-loader
来进行进一步的处理,为什么会将style-loader
放在前面呢?webpack
在读取使用的loader
的过程中,是按照从右向左
的顺序读取的。webpack.config.js
的配置如下:const path = require('path')module.exports = { // 入口:可以是字符串/数组/对象,这里我们入口只有一个,所以写一个字符串即可 entry: './src/main.js', // 出口:通常是一个对象,里面至少包含两个重要属性,path 和 filename output: { path: path.resolve(_dirname,'dist'),// 注意;path通常是一个绝对路径 filename: 'bundle.js' }, module: { rules: [ { test: /\.css$/, use: ['style-loader','css-loader'] } ] }}
less
、scss
、stylus
来写样式,webpack
是否可以帮助我们处理呢? less
为例,其他也是一样的。less
文件,依然放在css
文件夹中special.less
@fontSize: 50px;@fontColor: red;body{ color: @fontColor; font-size: @fontSize;}
main.js
const math = require('./js/mathUtils')console.log('Hello Webpack');console.log(math.add(10,20));console.log(math.mul(10,20));// 必须在这里引用一次css文件require('./css/normal.css')// 引入lessrequire('./css/special.less')// 为了查看less生效的代码,添加一个divdocument.writeln('Hello World')
less-loader
相关的使用说明loader
less
,因为webpack
会使用less
对less
文件进行编译npm install --save-dev less-loader less
rules
选项,用于处理.less
文件{ test: /\.less$/, use: [{ loader: "style-loader" // creates style nodes from JS strings },{ loader: "css-loader" // translates CSS into CommonJS },{ loader: "less-loader" // compiles Less to CSS }]}
test01.jpg
(小于8kb
),一张较大的图片test02.jpeg
(大于8kb
)css
样式中引用图片的情况,所以我更改了normal.css
中的样式:body{ background-color: red; background: url(../imgs/test01.jpeg)}
url-loader
来处理,依然先安装url-loader
npm install --save-dev url-loader
webpack.config.js
配置文件:{ test: /\.(png|jpg|gif|jpeg)$/, use: [ { loader: 'url-loader', options: { limit: 8192 } } ]}
index.html
,就会发现我们的背景图片选出了出来。 base64
显示出来的limit
属性的作用,当图片小于8kb
时,对图片进行base64
编码8kb
呢?我们将background
的图片改成test02.jpg
8kb
的图片,会通过file-loader
进行处理,但是我们的项目中并没有file-loader
file-loader
npm install --save-dev file-loader
dist
文件夹下多了一个图片文件 webpack
自动帮助我们生成一个非常长的名字 32位hash值
,目的是防止名字重复options
中添加上如下选项: img
:文件要打包到的文件夹name
:获取图片原来的名字,放在该位置hash
:8
:为了防止图片名称冲突,依然使用hash
,但是我们只保留8位
ext
:使用图片原来的扩展名options: { limit: 8192, name: 'img/[name].[hash:8].[ext]'}
webpack
会将生成的路径直接返回给使用者dist
文件夹下的,所以这里我们需要在路径下再添加一个dist/
// 出口:通常是一个对象,里面至少包含两个重要属性,path 和 filenameoutput: { path: path.resolve(_dirname,'dist'),// 注意:path通常是一个绝对路径 filename: 'bundle.js', publicPath: 'dist/'}
webpack
打包的js
文件,发现写的ES6
语法并没有转成ES5
,那么就意味着可能一些对ES6
还不支持的浏览器没有办法很好的运行我们的代码。ES6
的语法转成ES5
,那么就需要使用babel
。 webpack
中,我们直接使用babel
对应的loader
就可以了npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
webpack.config.js
文件{ test: /\.m?js$/, exclude: /{node_modules|bower_components}/, use: { loader: 'babel-loader', options: { presets: ['es2015'] } }}
bundle.js
文件,发现其中的内容变成了ES5
的语法Vuejs
进行开发,而且会以特殊的文件来组织vue
的组件。 webpack
环境中集成Vuejs
Vuejs
,那么必然需要对其有依赖,所以需要先进行安装 vue
的,所以并不是开发时依赖npm install vue --save
Vue
了import Vue from 'vue'new Vue({ el: '#app', data: { name: 'xxx' }})
{ {message}}
vue
的js
文件而已)runtime-only
版本的Vue
,什么意思呢? Vue
不同版本构建webpack
的配置,添加如下内容即可resolve: { alias: { 'vue$': 'vue/dist/vue.esm.js' }}
data
中的数据显示在界面中,就必须是修改index.html
index.html
来使用组件html
模板在之后的开发中,我并不希望手动的来频繁修改,是否可以做到呢?template
属性: Vue
实例中,我们定义了el
属性,用于和index.html
中的#app
进行绑定,让Vue
实例之后可以管理它其中的内容div
元素中的{ {message}}
内容删掉,只保留一个基本的id
为div
的元素{ {message}}
的内容,应该怎么处理呢?template
属性,代码如下:new Vue({ el: '#app', template: '{ { message}}data: { message: 'xxx' }})
HTML
代码结构el
和template
模板的关系是什么呢? el
用于指定Vue
要管理的DOM
,可以帮助解析其中的指令、事件监听等等Vue
实例中同时指定了template
,那么template
模板的内容会替换掉挂载的对应el
的模板index.html
,只需要在template
中写入对应的标签即可template
模块非常麻烦怎么办呢? template
模板中的内容进行抽离template
、script
、style
,结构变得非常清晰Vue
开发过程中,我们都会采用组件化开发的思想。 js
文件中,并且导出const App = { template: '{ {name}}
', data() { return { name: '我是APP组件' } }}new Vue({ el: '#app', template: `{ {message}}` data: { message: 'xxx' }, components: { App }})
js
对象的形式进行组织和使用的时候是非常不方便的 template
模块非常的麻烦vue
的组件{ {name}}
vue-loader
以及vue-template-compiler
vue-loader
和vue-template-compiler
npm install vue-loader vue-template-compiler --save-dev
webpack.config.js
的配置文件:{ test: /\.vue$/, use: ['vue-loader']}
plugin
是什么? plugin
是插件
的意思,通常是用于对某个现有的架构进行扩展webpack
中的插件,就是对webpack
现有功能的各种扩展
,比如打包优化
,文件压缩
等等loader
和plugin
区别 loader
主要用于转换某些类型的模块,它是一个转换器
plugin
是插件
,它是对webpack
本身的扩展,是一个扩展器
plugin
的使用过程: npm
安装需要使用的plugins
(某些webpack
已经内置的插件不需要安装)webpack.config.js
中的plugins
中配置插件webpack
打包过程进行扩容,让我们的webpack
变得更加好用BannerPlugin
,属于webpack
自带的插件。webpack.config.js
的文件:const path = require('path')const webpack - require('webpack')module.exports = { ... plugins: [ new webpack.BannerPlugin('最终版权归xxx所有') ]}
bundle.js
文件的头部index.html
文件是存放在项目的根目录
下的。 dist
文件夹中的内容,但是dist
文件夹中如果没有index.html
文件,那么打包的js
等文件也就没有意义了。index.html
文件打包到dist
文件夹中,这个时候就可以使用HtmlWebpackPlugin
插件HtmlWebpackPlugin
插件可以为我们做这些事情: index.html
文件(可以指定模板来生成)js
文件,自动通过script
标签插入到body
中HtmlWebpackPlugin
插件npm install html-webpack-plugin --save-dev
插件
,修改webpack.config.js
文件中plugins
部分的内容如下: template
表示根据什么模板来生成index.html
output
中添加的publicPath
属性script
标签中的src
可能会有问题plugins: [ new webpack.BannerPlugin('最终版权归xxx所有'), new htmlWebpackPlugin({ template: 'index.html' }),]
js
等文件进行压缩处理 js
文件进行压缩uglifyjs-webpack-plugin
,并且版本号指定1.1.1
,和CLI2
保持一致npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
webpack.config.js
文件,使用插件:const path = require('path')const webpack = require('webpack')const uglifyJsPlugin = require('uglifyjs-webpack-plugin')module.exports = { ... plugins: [ new webpack.BannerPlugin('最终版权归xxx所有') new uglifyJsPlugin() ]}
bunlde.js
文件,是已经被压缩
过了。webpack
提供了一个可选的本地开发服务器
,这个本地服务器
基于node.js
搭建,内部使用express框架
,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果。webpack
中使用之前需要先安装它npm install --save-dev webpack-dev-server@2.9.1
devserver
也是作为webpack
中的一个选项,选项本身可以设置如下属性: contentBase
:为哪一个文件夹提供本地服务,默认是根文件夹,我们这里要填写./dist
port
:端口号inline
:页面实时刷新historyApiFallback
:在SPA
页面中,依赖HTML5
的history
模式webpack.config.js
文件配置修改如下:scripts
: --open
参数表示直接打开浏览器devServer: { contentBase: './dist', inline: true}
"dev": "webpack-dev-server --open"
转载地址:http://xdqwi.baihongyu.com/