019 Vue webpack的使用
[A] webpack的简介
1. webpack是一个现代的JavaScript应用的静态模块打包工具
1. 在开发中,我们可能生成多种格式的文件,如.js, .hbs, .png, sass等等,而最终我们只需要.js, .png, .css文件
webpack可以帮助我们实现文件的自动打包和格式转换
2. 在开发中,模块化开发有很多规范,如CommonJS,AMD, CMD, ES6规范等,但是浏览器只支持ES6规范,缺乏支持其他规范的底层支撑
webpack可以提供这种底层支撑,使得开发时可以随意使用各种规范
3. 在开发中,模块化的开发会使得哥哥模块之间存在错综复杂的依赖,先后顺序处理不好会运行报错
webpack可以帮助我们自动化的处理各种依赖关系
4. 在webpack中,不仅.js被看作模块,图片,CSS,json文件等等都被看作是模块对待
2. webpack的两个核心是:模块和打包
模块:
1. 在ES6之前,我们要进行模块化开发,就要借助其他工具实现模块化,
并且在模块化开发完项目后,还要处理模块之间的依赖关系,将其整合打包
2. webpack的一个核心就是进行模块化,并且处理好模块之间的依赖关系
3. 在webpack中,js文件,css文件,图片,json文件都可以被视作模块来使用
打包:
1. 打包就是,webpack将隔俄国模块进行整理打包成一个或者多个包
2. 在打包的过程中可以对资源进行处理,
比如压缩图片,将scss转化成css,ES6语法转化成ES5语法,Typescript转化成JavaScript等等
3. webpack与gulp/grunt的对比
1. gulp/grunt的核心是task
首先,我们配置一系列的task,并且定义task要处理的事物(图片压缩,ES6版本转换,scss转成css)
然后,让gulp/grunt来自动化的执行这些task,而且整个流程自动化执行
因此,gulp/grunt被称为前端自动化任务管理工具
2. 什么时候用gulp/grunt
首先,工程模块依赖关系非常简单,甚至没有模块化的概念
其次,只需要进行简单的合并,压缩,使用gulp/grunt即可
但是,如果整个项目依赖关系复杂,使用模块化管理,就得考虑webpack了
3. 区别
gulp/grunt更加强调前端流程的自动化,模块不是它的核心
webpack更加强调模块化开发管理,而文件合并,图片压缩只是它的附带功能
4. webpack的运行依赖于node环境.
node环境为了能够执行更多的代码,其中包含了一个包管理器cpm(node package manager)
[B] webpack的安装
安装webpack(在某个nodejs版本里)
1. webpack全局安装
控制台指令:
npm install webpack -g
也可以指定webpack版本:
npm install webpack@3.6.0 -g
2. webpack本地安装:
控制台指令:
npm install webpack --save-dev
也可以指定webpack版本:
npm install webpack@3.6.0 --save-dev
为什么全局安装之后还要本地安装呢
因为在控制台(CMD控制台,console等平台)上运行的webpack命令时调用的是全局webpack
但在html,js文档中调用不到全局webpack指令,需本地下载
[C] webpack基本使用
使用场景:
1. 现有A.js模块中定义了若干方法,在B.js中需要导入A.js中的方法并使用
2. 但A.js中使用到的模块化导入导出方法(CommomJS, ES6等)无法在直接在node或者浏览器中运行
3. 通过webpack打包,将无法运行的文件转化成可以运行的文件,再进行后续操作
使用步骤:
1. 编写A.js文件
// A.js
var out = {
name: 'Carrey',
run: function(){
console.log('I am Carrey, I can run!')
}
}
export default out
2. 在B.js中导入A.js
// B.js
import obj from './A.js'
console.log(obj.name)
obj.run()
3. 使用webpack对B.js进行打包,保存到对应的路径中
1. 先切换到B.js所在的路径下
2. 终端运行指令:
webpack B.js -o ./dist
// 即将B.js打包到dist文件夹下
执行后,打包好的文件保存在dist/main.js中
4. 运行打包好的文件
1. 在node中运行:
node main.js
2. 在浏览器中运行:
<script src="./main.js"></script>
[D] webpack 的配置文件
webpack的配置文件有两个:webpack.config.js和package.json的配置,配置好这两个文件后,我们在控制台直接运行webpack,即可将指定的文件打包并放在指定的位置
1. 配置webpack.config.js文件
1. 指定默认的入口文件名,默认为main.js
2. 指定默认的出口文件名, 默认为bundle.js
添加package.json文件:
1. 在当前目录下,新建一个文件,名为webpack.config.js、
2. 在该文件中添加内容如下:
const path = require("path"); module.exports = { entry: "./src/main.js", output: { path: path.resolve(__dirname, 'dist'), // path是一个模块,resolve方法是将导入的两个路径进行连接 // __dirname指的是当前文件所在的路径 filename: "bundle.js" } }
2. 配置package.json文件
记录node中开发的配置信息
1. 在该文件中,可以将webpack指令和npm run 指令对应起来
如在package.json文件中的script对象中添加:
build: "webpack",
则此后,在控制台输入npm run build,等价于输入webpack
2. 在终端和CMD控制台运行的webpack命令都是调用全局的webpack包,
而package.json中的script中的指令首先查找本地的webpack包,若没有找到再去全局查找
[E] webpack中的loader
loader时webpack中的一个非常核心的概念,loader是一个哦你沟通的概念,并非指某一个文件或者插件
1. loader能做什么
1. webpack可以处理js文件,并且处理js文件之间的依赖关系。
2. 到那时开发中,除了处理js文件,还要处理css, 图片,sass和less转为css,
ES6转为ES5, TypeScript转化为ES5 .jsx, .vue转化为js文件等等内容
3. webpackk本身解决不了这么多问题,但是webpack拓展的loader可以处理这些问题
2. loader的使用
1. 通过npm本地安装loader
安装地址:https://www.webpackjs.com/concepts/
安装指令:npm install --save-dev loader名
2. 在入口文件中导入所需要打包的文件(.css, png,等等一系列文件),使得入口文件依赖于这些文件,方便打包
即在main.js文件中添加命令:
require("文件");
3. 在webpack.config.js中的modules关键字下进行配置
将下载的loader告诉webpack.config.js文件,即在该文件中新增一个module对象。
module对象:
module: { rules: [ { test: /\.css$/, use: ["loader名"] } ] }
loader的使用示例1: 配置并使用.css打包工具
1. 编写一个.css文件,命名为cssStyle.css
2. 在webpack的入口文件中导入该css模块,使得入口文件依赖于cssStyle.css文件
具体操作:
在入口文件中加入指令:
require("../css/cssStyle.css");
3. 本地下载和安装css打包的工具
下载地址:https://www.webpackjs.com/concepts/
具体操作:
npm install --save-dev css-loader
npm install style-loader --save-dev
4. 配置webpack.config.js文件
在webpack.config.js文件的module.exports对象中新增一个module对象
module对象:
module: { rules: [ { test: /\.css$/, use: [ { loader: "style-loader" }, { loader: "css-loader" } ] } ] }
【注】style-loader:将模块的导出作为样式添加到 DOM 中
css-loader: 解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码
在use中的读取顺序是从右向左,这两个文件的顺序不能错
loader的使用示例2: 配置并使用.less打包工具
1. 编写一个.less文件,命名为lessStyle.less
2. 在webpack的入口文件中导入该less模块,使得入口文件依赖于lessStyle.less文件
具体操作:
在入口文件中加入指令:
require("../css/lessStyle.less");
3. 本地下载和安装css打包的工具
下载地址:https://www.webpackjs.com/concepts/
具体操作:
npm install --save-dev less-loader
npm install --save-dev style-loader
npm install less --save-dev
4. 配置webpack.config.js文件
在webpack.config.js文件的module.exports对象中的module对象中的rules数组中新增一个数组元素
{ test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"] }
loader的使用示例3: 配置并使用图片打包工具
当css,js文件中有图片时,需要下载打包图片的loader
1. 本地下载和安装css打包的工具
下载地址:https://www.webpackjs.com/concepts/
具体操作:
npm install --save-dev url-loader
2. 配置webpack.config.js文件
在webpack.config.js文件的module.exports对象中的module对象中的rules数组中新增一个数组元素
{ test: /\.(png|jpg|gif)$/, use: [ { loader: 'url-loader', options: { // 图片大小限制,单位为B // 当图片实际大小在limit范围内时,只下载url-loader即可,图片会被转化为base64格式的文件 // 当图片大小超过limit范围是,还要瞎子啊file-loader,此时图片会以哈希值命名并保存到目标文件夹中 // 此时,文件调用会因为路径变了而报错,因此须在本配置文件的output对象中添加元素:publicPath: "dist/" limit: 1500, // 这里的name值是对打包的图片的路径和名字做限制的 name: "img/[name].[hash:8].[ext]" } } ] }
loader的使用示例4: ES6转化成ES5的babel
ES6中的一些语法在ES5中不支持,为了更大限度的兼容,有时候需将ES6转化成ES5
1. 本地下载和安装css打包的工具
下载地址:https://www.webpackjs.com/concepts/
具体操作:
npm install babel-loader babel-core babel-preset-es2015
【注】版本要对的上使用时才不会报错
检查:
"babel-loader": "^7.1.5",
"babel-core": "^6.26.3",
"babel-preset-es2015": "^6.24.1",
2. 配置webpack.config.js文件
在webpack.config.js文件的module.exports对象中的module对象中的rules数组中新增一个数组元素
{ test: /\.js$/, // exclude排除,即在node_modules|bower_components这两个文件夹中的js不参与打包 exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['es2015'] } } }
[F] plugin的使用
1. plugin使插件的意思,通常指用于对现有的架构进行拓展
2. webpack中的插件,及时对webpack中现有功能的拓展,比如打包优化,文件压缩等等
3. loader与plugin的区别
1. loader主要用于转换某些文件的模块,他是一个转换器
2. plugin是插件,是对webpack本身的扩展,是一个扩展器
4. plugin的使用
1. 通过npm安装需要的plugins(某些wbpack内置的插件不需要安装)
2. 在webpack.config.js中的plugins中配置插件
plugin使用案例:
1. 添加版权说明 BannerPlugin插件
1. BannerPlugin插件是webpack自带的一个插件,在webpack.config.js中直接导入webpack包即可
const webpack = require("webpack");
2. 在webpack.config.js文件中的module.exports内添加plugins元素:
plugins:[
new webpack.BannerPlugin("最终版权归Carrey所有")
]
2. 打包html文件的插件:HtmlWebpackPlugin插件
1. 安装HtmlWebpackPlugin插件
npm install html-webpack-plugin --save-dev
2. 在webpack.config.js文件中的plugins中添加配置信息
const HtmlWebpackPlugin = require("html-webpack-plugin");
new HtmlWebpackPlugin({
template:'index.html'
// 以这个文件为模板生成html文件
})
3. 压缩js文件的插件:uglifyjs插件
1. 安装uglifyjs插件
npm install uglifyjs-webpack-plugin --save-dev
2. 在webpack.config.js文件中的plugins中添加配置信息
const uglifyjsPlugin = require("uglifyjs-webpack-plugin");
new uglifyjsPlugin()
[G] webpack中配置vue
如果在项目中需要使用vue,则需要先安装,由于开发完之后依然依赖vue,因此vue是运行时依赖
1. 安装vue:npm run vue --save
2. 安装vue的三种方式:
1. 直接下载vue.js引用
2. CND引入
3. npm安装vue模块
3. 引入vue实例
1. 在main.js中引入vue模块,并创建vue实例
import Vue from 'vue' const app = new Vue({ el: "#app", data: { msg: 'hello Carrey' } })
2. 将创建的这个app实例添加到index.html文件中
<body> <div id="app"> <h2>{{msg}}</h2> </div> </body>
4. 在上述3中会出现引用失败或无效的情况
原因:
vue在发布的时候有两个版本,分别是runtime-only和runtime-compiler
1. runtime-only 该版本不允许代码中有任何的template,因为无法编译
2. runtime-compiler 该版本允许代码中有template,因为有专门的模块进行解析
3. 而我们在main.js中通过 el: "#app" 方式引入的就是在index.html中定义的template模板
解决:
1. 在webpack.config.js中进行相关配置,如下:
输出元素中添加resolve元素
module.exports = { resolve: { // alias: 别名 alias: { 'vue$': 'vue/dist/vue.esm.js' } } }
解决原理:
1. 引用vue模块式默认引用的是vue发布的runtime-only版本,但是该版本不能编译template模板
2. 通过webpack.config.js中的配置(如上配置),就可以指定引用的vue文件为vue.esm.js,
这是一个runtime-compiler版本,就可以编译template模板了
5. vue实例中,el与template的区别
在上述3引入vue实例时,我们是将模板内容写在index.html中
即:
<body> <div id="app"> <h2>{{msg}}</h2> </div> </body>
而实际开发中,我们不把模板内容写在index.html文件中,而是写在main.js中创建的实例中
即:
import Vue from 'vue' const app = new Vue({ el: "#app", template: ` <div id="app"> <h2>{{msg}}</h2> </div> ` data: { msg: 'hello Carrey' } }
此时index.html文件中只保留引入实例的div
即:
<body> <div id="app"> </div> </body>
那么el和template到底什么关系呢 ?
实际上我们在实际开发中,不希望频繁修改index.html中的内容,
但是我们又需要频繁修改index.html中显示的内容(即index.html中的模板内容),怎么办呢
使用el时,我们在vue实例中通过el属性与index.html中的#app绑定,之后vue实例就可以管理其中的内容了
而当同时定义了el属性和template属性时,template中定义的模板会替换掉el绑定的那个组件的内容
6. 组件模板的抽离及vue的终极使用方案
在上述5中的使用方案中,我们可以进一步将组件抽离,以简化Vue实例
1. 在Vue实例中,我们可以将模板,数据以及方法全都抽出来
2. 将抽离出来的内容组合成一个组件,写在.vue文件中
3. 在vue实例中将这个.vue文件当作一个子组件,在Vue实例中引入并注册。
解决.vue文件通过webpack打包报错的问题:
1. 这是因为.vue文件,webpack并不认识,无法加载
2. 通过配置对应的loader帮助加载
npm install vue-loader vue-template-compiler --save-dev
3. 在webpack.config.js中进行相关配置
module:{ rules: [ { test: /\.vue$/, use: ['vue-loader'] } ] },
4. 若此时通过npm run build 打包文件报错,需要如下操作:
遇到报错注意查看报错信息
1. 在webpack.config.js中需要安装配套的plugin
// webpack.config.js const VueLoaderPlugin = require('vue-loader/lib/plugin') module.exports = { // ... plugins: [ new VueLoaderPlugin() ] }
[H] webpack搭建本地服务器 webpack-dev-server插件
在开发过程中,一旦修改保存代码,我们就希望看到运行结果,但是每次都需要webpack打包,然后手动运行,这样过于繁琐
因此我们可以搭建本地服务器,代码发生变动后,自动编译执行并展示在浏览器上
1. webpack-dev-server简介
这是webpack提供的一个可选的本地开发服务器,这个本地服务器是给予nodejs搭建的,内部使用express框架,可以实现想要的让浏览器自动刷新显示我们修改后的结果
2. 安装 webpack-dev-server
终端运行:npm install webpack-dev-server --save-dev
这个服务器只在开发时便于观察所写代码的运行结果,运行时不需要,因此为开发时依赖。
3. 在webpack.config.js文件中的module.exports中新增添加配置信息
devServer:{
contentBase: "./dist",
inline: true
}
4. 使用本地webpack-dev-server插件启动这个服务器
在package.json中配置script指令,使用本地包启动服务器
"dev": "webpack-dev-server"
5. 当使用npm run webpack-dev-server运行这个服务器时,就会启动一个服务器
当我们需要这个服务器自动打开浏览器网页时,可以将第3步中的指令改为:"dev": "webpack-dev-server --open"
[ I ] 配置文件的抽离
webpack.config.js中的配置文件显的有写冗杂,开发时我们需要将该配置文件进行分离 。
将基本的配置信息单独写在一个文件中,将仅在开发时依赖的配置信息单独写在一个配置文件中,将仅在运行时依赖的配置信息单独写在一个配置文件中。
1. 我们将配置文件webpack.config.js拆分成三个文件:基本配置 base.config.js文件,开发时依赖配置 dev.config.js文件 和 运行时依赖配置 prod.config.js文件。
2. 原webpack.config.js文件中,存在的属性:
1. entry:入口文件路径
2. output:目标文件路径
3. module:loader配置信息
4. resolve:解决模块请求时的问题
5. plugins:配置插件
6. devServer:搭建本地服务器
const path = require("path"); const webpack = require("webpack"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const uglifyjsPlugin = require("uglifyjs-webpack-plugin"); module.exports = { entry: "./src/js/main.js", output: { path: path.resolve(__dirname, 'dist'), // path是一个模块,resolve方法是将导入的两个路径进行连接 // __dirname指的是当前文件所在的路径 filename: "bundle.js", // 保存图片的地址 // publicPath: "dist/" }, module: { rules: [ { test: /\.css$/, use: ["style-loader","css-loader" ] }, { test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"] }, { test: /\.(png|jpg|gif)$/, use: [ { loader: 'url-loader', options: { // 图片大小限制,单位为B limit: 1500, name: "img/[name].[hash:8].[ext]" } } ] }, { test: /\.js$/, // exclude排除,即在node_modules|bower_components这两个文件夹中的js不参与打包 exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['es2015'] } } }, { test: /\.vue$/, use: ["vue-loader"] } ] }, resolve:{ // alias 别名 alias:{ "vue$": "vue/dist/vue.esm.js" } }, plugins:[ new webpack.BannerPlugin("最终版权归Carrey所有"), new HtmlWebpackPlugin({ template:'index.html' }), new uglifyjsPlugin(), ], devServer: { contentBase: "./dist", inline: true } }
3. 基本配置文件 base.config.js文件
1. entry:入口文件路径
2. output:目标文件路径
3. module:loader配置信息
4. resolve:解决模块请求时的问题
const path = require("path"); const webpack = require("webpack"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const uglifyjsPlugin = require("uglifyjs-webpack-plugin"); module.exports = { entry: "./src/js/main.js", output: { path: path.resolve(__dirname, 'dist'), // path是一个模块,resolve方法是将导入的两个路径进行连接 // __dirname指的是当前文件所在的路径 filename: "bundle.js", // 保存图片的地址 // publicPath: "dist/" }, module: { rules: [ { test: /\.css$/, use: ["style-loader","css-loader" ] }, { test: /\.less$/, use: ["style-loader", "css-loader", "less-loader"] }, { test: /\.(png|jpg|gif)$/, use: [ { loader: 'url-loader', options: { // 图片大小限制,单位为B limit: 1500, name: "img/[name].[hash:8].[ext]" } } ] }, { test: /\.js$/, // exclude排除,即在node_modules|bower_components这两个文件夹中的js不参与打包 exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['es2015'] } } }, { test: /\.vue$/, use: ["vue-loader"] } ] }, resolve:{ // alias 别名 alias:{ "vue$": "vue/dist/vue.esm.js" } }, }
4. 开发时依赖的配置文件 dev.config.js 文件
6. devServer:搭建本地服务器
// dev.config.js module.exports = { devServer: { contentBase: "./dist", inline: true } }
5. 运行时依赖的配置文件 prod.config.js文件
5. plugins:配置插件
// prod.config.js const uglifyjsPlugin = require("uglifyjs-webpack-plugin"); module.exports = { plugins:[ new webpack.BannerPlugin("最终版权归Carrey所有"), new HtmlWebpackPlugin({ template:'index.html' }), new uglifyjsPlugin(), ], }
6. 文件的合并
配置文的分离是为了便于开发,但分离的配置文件最终还是要合并的
1. 安装webpack-merge包,用于合并文件
终端运行:npm install webpack-merge --save-dev
开发时依赖,运行时不需要
2.dev.config.js文件的合并,在配置文件中调用webpack-merge包,对文件进行合并
// dev.config.js // 导入webpack-merge包,用于合并文件 const webpackMerge = require('webpack-merge') // 导入基本配置文件,并将其和本文件进行合并后导出 const baseConfig = require('./base.config.js') module.exports = webpackMerge(baseConfig,{ devServer: { contentBase: "./dist", inline: true } })
3. prod.config.js文件的合并,在配置文件中调用webpack-merge包,对文件进行合并
// prod.config.js const uglifyjsPlugin = require("uglifyjs-webpack-plugin"); // 导入webpack-merge包 const webpackMerge = require('webpack-merge') // 导入基本配置文件,并将其与本文件合并后到处 const baseConfig = require('./base.config.js') module.exports = webpackMerge(baseConfig,{ plugins:[ new webpack.BannerPlugin("最终版权归Carrey所有"), new HtmlWebpackPlugin({ template:'index.html' }), new uglifyjsPlugin(), ], })
4. 至此,配置文件的拆分和合并都完成了,可以删掉原来的配置文件webpack.config.js了
7. 配置文件合并后,无法直接使用该配置文件,会出现两个问题
问题1:提示没有找到配置文件webpack.config.js,这是因为vue默认的配置文件名为webpack.config.js,而现在只有base.config.js文件,dev.config.js文件 和 prod.config.js文件
解决:
在package.json文件中人为的指定配置文件
"scripts": { // 这里的./build/prod.config.js和./build/prod.config.js分别为配置文件所在路径 "build": "webpack --config ./build/prod.config.js", "dev": "webpack-dev-server --open --config ./build/prod.config.js", },
问题2:打包后的文件没有保存在指定的dist文件中,而是在配置文件 prod.config.js 的路径下
这是因为在base.config.js中,output出口文件路径为 path: path.resolve(__dirname, 'dist'), 这里__dirname获取的是当前路径,即合并到prod.config.js 后的路径(即 prod.config.js 的路径)
解决:
在出口文件中的路径改为:path: path.resolve(__dirname, '../dist') 返回上一层的dist文件夹中,实际在哪根据需要修改