本篇笔记使用的
webpack版本为3.6.0 ,因为vue cli2依赖于这个版本
什么是webpack
官方解释:At its core, **webpack **is a static module bundler for modern JavaScript applications.
从本质上来讲,webpack是一个现代的JavaScript应用的静态模块打包工具。
和grunt/gulp的对比
-
grunt/gulp的核心是Task
- 我们可以配置一系列的task,并且定义task要处理的事务(例如ES6、ts转化、图片压缩、scss转专成css)
- 之后让grunt/gup来依次执行这些task,而且让整个流程自动化。
- 所以 grunt/gulp也被称为前端自动化任务管理工具。
-
我们来看一个gulp的task
- 下面的task就是将src下面的所有js文件转成ES5的语法。
- 并且最终输出到dist文件夹中。
const gulp = require('gulp'); const babel = require('gulp-babel'); gulp.task('js',()=>{ gulp.src('src/*.js') .pipe(babel({ presets:['es2015'] })) .pipe(gulp.dest('dist')) }); -
什么时候用 grunt/gulp呢?
- 如果你的工程模块依赖非常简单,甚至是没有用到模块化的概念。
- 只需要进行简单的合并、压缩,就使用 grunt/gulp即可。
- 但是如果整个项目使用了模块化管理,而且相互依赖非常强,我们就可以使用更加强大的 webpack了。
-
所以,grunt/gulp和 webpack有什么不同呢?
- grunt/gulp更加强调的是前端流程的自动化,模块化不是它的核心。
- webpack更加强调模块化开发管理,而文件压缩合并、预处理等功能,是他附带的功能。
webpack起步
一般项目结构
- dist文件夹 distribution 发布后将这个文件夹部署到服务器即可
- src文件夹 用来存放代码文件
打包
//在src文件夹中的main.js
const xx = require('./other');
console.log(xx.add(1,2));
//在src文件夹中的other.js
function add(num1,num2){
return num1+num2;
}
let a = 999;
module.exports = {add,a}
#进入项目文件夹后
webpack ./scr/main.js ./dist/bundle.js
#webpack 入口文件 目标文件
配置打包
在项目根目录下创建webpack.config.js文件,文件名必须是这个
//在此之前最好npm init一下
//webpack.config.js内容
const path = require('path');
module.exports={
entry:'./src/main.js',
output:{
path:path.join(__dirname,'./dist'),
filename:'bundle.js'
}
}
形成映射
//npm init 初始化文件 package.json
{
"name": "start",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"//npm run test执行这条命令,类同
"build":"webpack"//以后使用npm run build 替代 webpack 而且会优先找本地的webpack而非全局
},
"author": "me",
"license": "ISC"
}
文件处理
CSS文件处理
-
安装
css-loader和style-loadernpm install css-loader --save-dev #--save-dev为开发时依赖 #--save-dev的模块,在npm install的时候不会被下载到node_modules文件夹中,而--save会 -
配置
webpacka..config.jsconst path = require('path'); module.exports={ entry:'./src/main.js', output:{ path:path.join(__dirname,'./dist'), filename:'bundle.js' },//下面这段 module:{ rules:[ { test:/\.css$/,//切记注意这里不是字符串,是正则表达式 // css-loader只负责将css文件进行加载 // style-loader负责将样式添加到DOM中 // 读取loader的顺序是从右向左 use:['style-loader','css-loader'] } ] } } -
将CSS文件作为模块,按照
require方法导入main.jsconst xx = require('./js/other'); require('./css/common.css'); console.log(xx.add(1,2)); -
执行打包代码
Less文件处理
-
安装
less-loader和less#npm install less-loader less --save-dev -
配置
webpacka..config.jsconst path = require('path'); module.exports={ entry:'./src/main.js', output:{ path:path.join(__dirname,'./dist'), filename:'bundle.js' }, module:{ rules:[ { test:/\.css$/, // css-loader只负责将css文件进行加载 // style-loader负责将样式添加到DOM中 // 使用顺序是从右向左 use:['style-loader','css-loader'] },//添加下面这段 { test: /\.less$/, use:['style-loader','css-loader','less-loader'] // 将 Less 编译为 CSS } ] } } -
将less文件作为模块,按照
require方法导入main.jsconst xx = require('./js/other'); require('./css/common.css'); require('./css/special.less'); console.log(xx.add(1,2)); -
打包
图片文件处理
-
安装
url-loader和file-loadernpm install url-loader file-loader --save-dev -
配置
webpacka..config.js{ test: /\.(png|jpg|gif|jpeg)$/, use:[ { loader:'url-loader', options:{ limit:8192//只处理<8kb的图片,会将图片转为base64类型的字符串 //在图片>8kb的时候,会去寻找file-loader来处理 //默认被file-loader打包好的名字为32位的哈希值,是为了防止重复等等 //但是在真正项目开发中,并不是适合,所以添加name选项 name:'img/[name].[hash:8].[ext]' //这样把图片文件放到dist文件夹下的img文件夹下 //[name]为文件原名+[hash:8]8位哈希值防重复+[ext]后缀名 } } ] } -
被
file-loader打包的图片会到dist文件夹中,由于路径不对,即使打包成功也不会显示图片,需要再配置一下webpack.config.jsconst path = require('path'); module.exports={ entry:'./src/main.js', output:{ path:path.join(__dirname,'./dist'), filename:'bundle.js', publicPath:'dist/'//添加公共路径 }, module:{ //... } } -
打包
Vue文件处理
-
安装
vue-loader,vue-template-compilernpm install vue-loader@13 vue-template-compiler --save-dev #15.*之后版本需要一个插件,不知道是什么 -
配置
webpack-config.js{ test:/\.vue$/, use:['vue-loader'] } -
打包
Babel
webpack打包完后,仔细观察浏览器中的JS代码,发现代码还是ES6版本,但是为了多浏览器支持,必须要转化为ES5,这里使用Babel来转化ES6到ES5。
-
安装
babelnpm install babel-loader@7 babel-core babel-preset-es2015 --save-dev #按教程安装7版本,为了防止错误 -
配置
webpack.config.jsmodule: { rules: [ { test: /\.m?js$/, exclude: /(node_modules|bower_components)/,//表示排除(不匹配)这些文件夹 use: { loader: 'babel-loader', options: { presets: ['es2015'] } } } ] } -
打包
配置Vue
-
安装Vue
npm install vue --save -
配置
webpack.config.jsmodule.exports={ resolve:{ alias:{ 'vue$':'vue/dist/vue.esm.js' //默认会找node_modules/vue/dist/vue.runtime.js,但这个运行时不会解析template模板 //所以在这里配置,主动更改默认Vue版本 } } } -
使用Vue
import Vue from 'vue' const app = new Vue({ el:'#app', data:{ message:'我是测试内容' } }) -
打包
Vue项目的终极方案
- 某Vue方案
dist打包生成的文件放入该该文件夹node_modulesnpm下载的包src资源cssjsimgvue- 各种
.vue文件,相互注册,形成树结构
- 各种
main.js引入vue文件根结构和各种js文件...
index.html主页package.jsonnpm init 生成package-lock.jsonnpm init 生成webpack.config.jswebpack配置
plugin插件的使用
简单使用横幅插件
配置webpack.config.js
const webpack = require('webpack');
plugins:[
new webpack.BannerPlugin("本项目版权归wc所有")
]
以后打包的bundle.js文件第一行为/*本项目版权归wc所有*/
打包html的plugin
-
目前,我们的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可能会有问题
const HtmlWebpackPlugin = require('html-webpack-plugin');
//部分代码
plugins:[
new webpack.BannerPlugin("本项目版权归wc所有"),
new HtmlWebpackPlugin({
template:'index.html'
})
]
因为打包完后bundle.js和index.html在同一目录下,所以需要对webpack.config.js配置
// publicPath:'dist/' 将这个注释掉或者删除
JS压缩的Plugin
-
在项目发布之前,我们必然需要对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() ] } -
查看打包后的bundle.js文件,是已经被压缩过了的。
该插件和横幅插件冲突,因为该插件会删除所有注释
webpack-dev-server搭建本地服务器
-
webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js搭建,内部使用Express框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果。
-
不过它是一个单独的模块,在webpack中使用之前需要先安装它
npm install -save-dev webpack-dev-server@2.9.1 -
devServer也是作为webpack中的一个选项,选项本身可以设置如下属性:
contentBase:为哪一个文件夹提供本地服务,默认是根文件夹,我这里要填写./distport:端口号inline:页面实时刷新historyApiFallback:在SPA页面中,依赖HTML5的history模式
-
webpack.config.js文件配置修改如下:
devServer:{ contentBase: './dist', inline: true } -
我们可以再配置另外一个scripts:
--open参数表示直接打开浏览器
'dev':'webpack-dev-server --open'
与图中2.9.1修改为2.9.3,为了和webpack版本对应
配置文件的抽离
开发中会遇到这样的问题:当我们要进行调试测试时需要打包项目,但是配置文件中的uglify插件会让压缩JS代码,这样反而不好修改JS文件的代码了。而在真正上线项目时,也不需要搭建本地服务器,所以devServer选项也不需要。
所以我们要把webpack.config.js文件分离成多个版本。
安装webpack-merge
npm install webpack-merge@4.1.5 --save-dev
#用与合并配置文件
分离
原始webpack.config.js如下
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const uglify = require('uglifyjs-webpack-plugin');
module.exports={
entry:'./src/main.js',
output:{
path:path.join(__dirname,'./dist'),
filename:'bundle.js',
// publicPath:'dist/'
},
module:{
rules:[
{
test:/\.css$/,
// css-loader只负责将css文件进行加载
// style-loader负责将样式添加到DOM中
// 使用顺序是从右向左
use:['style-loader','css-loader']
},
{
test: /\.less$/,
use:['style-loader','css-loader','less-loader'] // 将 Less 编译为 CSS
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use:[
{
loader:'url-loader',
options:{
limit:8192,//只处理小于8kb的图片
name:'img/[name].[hash:8].[ext]'
}
}
]
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,//表示排除(不匹配)这
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
},
{
test:/\.vue$/,
use:['vue-loader']
}
]
},
resolve:{
alias:{
'vue$':'vue/dist/vue.esm.js'
}
},
plugins:[
new webpack.BannerPlugin("本项目版权归wc所有"),
new HtmlWebpackPlugin({
template:'index.html'
}),
new uglify()//这个在调试中不需要
],
devServer:{//这个在上线时不需要
contentBase:'./dist',
inline:true
}
}
我们在项目根目录下创建一个build文件夹,结构如下
buildbase.config.js存放公共配置pro.config.js存放上线需要的配置dev.config.js存放开发时需要的配置
base.config.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports={
entry:'./src/main.js',
output:{
path:path.join(__dirname,'./dist'),
filename:'bundle.js',
// publicPath:'dist/'
},
module:{
rules:[
{
test:/\.css$/,
// css-loader只负责将css文件进行加载
// style-loader负责将样式添加到DOM中
// 使用顺序是从右向左
use:['style-loader','css-loader']
},
{
test: /\.less$/,
use:['style-loader','css-loader','less-loader'] // 将 Less 编译为 CSS
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use:[
{
loader:'url-loader',
options:{
limit:8192,//只处理小于8kb的图片
name:'img/[name].[hash:8].[ext]'
}
}
]
},
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,//表示排除(不匹配)这
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
},
{
test:/\.vue$/,
use:['vue-loader']
}
]
},
resolve:{
alias:{
'vue$':'vue/dist/vue.esm.js'
}
},
plugins:[
new webpack.BannerPlugin("本项目版权归wc所有"),
new HtmlWebpackPlugin({
template:'index.html'
})
]
}
pro.config.js
const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config.js')
module.exports=webpackMerge(baseConfig,{
devServer:{
contentBase:'./dist', //基于dist文件夹
inline:true //实时更新
}
})
dev.config.js
const uglify = require('uglifyjs-webpack-plugin');
const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config.js')
module.exports=webpackMerge(baseConfig,{
plugins:[
new uglify()
]
})
分离后
-
删除
webpack.config.js -
修改
package.json"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack --config ./build/pro.config.js",//--config 指定配置文件 "dev": "webpack-dev-server --open --config ./build/dev.config.js" },