15 小程序-VUE-webpack各类配置操作使用
1.webpack
1.1认识webpack
At its core, webpack is a static module bundler for modern JavaScript applications. 从本质上来讲,webpack是一个现代的JavaScript应用的静态模块打包工具,p两个点来解释上面这句话:模块 和 打包
可以理解为:我们开发项目中很多文件,js,hbs,sass,png。如果贸然直接给服务器部署,那么浏览器可能不支持,比方说sass浏览器不支持,需要一些工具打包识别转换,则遇到打包工具很多种,比如webpack,grunt,rollup(vue源码基于rollup构建)
webpack模块化概念:
没有webpack,则浏览器仅能支持es6模块化语法,那么在webpack里面就可以使用amd,cmd,commonjs进行模块化开发,后期进行转化,而不是简单转化为es6(可能部分浏览器不支持es6).而且不仅仅是JavaScript文件,我们的CSS、图片、json文件等等在webpack中都可以被当做模块来使用(在后续我们会看到)。
打包概念
- 理解了webpack可以帮助我们进行模块化,并且处理模块间的各种复杂关系后,打包的概念就非常好理解了。
- 就是将webpack中的各种资源模块进行打包合并成一个或多个包(Bundle)。
- 并且在打包的过程中,还可以对资源进行处理,比如压缩图片,将scss转成css,将ES6语法转成ES5语法,将TypeScript转成JavaScript等等操作。
- 但是打包的操作似乎grunt/gulp也可以帮助我们完成,它们有什么不同呢?
和ngrunt/gulp区别-grunt/gulp的核心是Task
- 我们可以配置一系列的task,并且定义task要处理的事务(例如ES6、ts转化,图片压缩,scss转成css)
- 之后让grunt/gulp来依次执行这些task,而且让整个流程自动化。
- 所以grunt/gulp也被称为前端自动化任务管理工具。
什么时候用grunt/gulp呢?
- 如果你的工程模块依赖非常简单,甚至是没有用到模块化的概念。
- 只需要进行简单的合并、压缩,就使用grunt/gulp即可。
- 但是如果整个项目使用了模块化管理,而且相互依赖非常强,我们就可以使用更加强大的webpack了。
所以,grunt/gulp和webpack有什么不同呢?
- grunt/gulp更加强调的是前端流程的自动化,模块化不是它的核心。
- webpack更加强调模块化开发管理,而文件压缩合并、预处理等功能,是他附带的功能。
1.2 webpack的安装
webpack依赖node环境,而node为了帮助我们管理更多的代码,自带工具npm帮忙我们进行依赖包管理。npm-node packages manager
全局安装webpack(这里我先指定版本号3.6.0,因为vue cli2依赖该版本,2里面webpack配置比较清晰)
- 局部安装webpack(后续才需要)-save-dev`是开发时依赖,项目打包后不需要继续使用的。
为什么全局安装后,还需要局部安装呢?
- 在终端不管是cmd还是idea直接执行webpack命令,使用的全局安装的webpack
- 当在idea里面terminal中遇到package.json中定义了scripts时,其中包含了webpack命令,那么使用的是局部webpack
1.3 webpack的起步
我们创建如下文件和文件夹:文件和文件夹解析:
- dist文件夹:用于存放之后打包的文件 disturbtion(发布)
- src文件夹:用于存放我们写的源文件
main.js:源文件,是项目的入口文件。具体内容查看下面详情。
mathUtils.js:定义了一些数学工具函数,可以在其他地方引用,并且使用。具体内容查看下面的详情。
- index.html:浏览器打开展示的首页html
- package.json:通过npm init生成的,npm包管理的文件(暂时没有用上,后面才会用上)
mathUtils.js文件中的代码:
main.js文件中的代码:
webpack ./src/main.js ./dist/bundle.js 就是将src的main.js打包至dist/bundle.js。然后在index.html中引用bundle.js即可使用
1.4 webpack的配置
传统 webpack ./src/main.js ./dist/bundle.js 需要手动给予入口文件js和目标文件js。我们可以进行单独配置,这样终端输入webpack即可自动识别。package.json是一个项目,单独做个依赖环境配置时候使用。
这个需要npm install,产生package.json,里面包含一些项目文件配置信息,然后在webpack.config.js中输入 const path=requrie('path')。后面path会在环境变量中查找,然后全局搜索配置的 path:path.resolve(__dirname,'dist'), 进行__dirname,'dist'两个进行拼接成为绝对路径。此处__dirname是自带关键字。不用定义。如此 webpack自识别,当然做映射后,和npm run build/serve是一个用途。都可以启动项目。我们映射在package.json中进行配置
这样配置的好处是运行build时,优先找的是本地webpack。找不到再去全局的。
- 开发时依赖package.json中 devDependencies。不用写,npm install按照时候自动添加
- 运行时依赖dependencies。
const path=require('path')
module.exports={
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'dist'),
filename:'bundle.js'
},
}
const path=require('path')
module.exports={
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'dist'),
filename:'bundle.js'
},
}
但是,每次执行都敲这么一长串有没有觉得不方便呢?OK,我们可以在package.json的scripts中定义自己的执行脚本。
- package.json中的scripts的脚本在执行时,会按照一定的顺序寻找命令对应的位置。
- 首先,会寻找本地的node_modules/.bin路径中对应的命令。
- 如果没有找到,会去全局的环境变量中寻找。
- 如何执行我们的build指令呢?
1.5 loader的使用-是webpack的扩展
loader就是使得css样式配置文件也像main.js mathUtils.js文件一样,都做模块化处理。loader是webpack中一个非常核心的概念。在开发中我们不仅仅有基本的js代码处理,我们也需要加载css、图片,也包括一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等等。
webpack本身的能力来说,对于这些转化是不支持的。那怎么办呢?给webpack扩展对应的loader就可以啦
- 步骤一:通过npm安装需要使用的loader
- 步骤二:在webpack.config.js中的modules关键字下进行配置
webpack也不可能找到它,因为我们只有一个入口main.js,webpack会从入口开始查找其他依赖的文件。在入口文件中引用:
我们一般多种文件的loader都去webpack.js.org中查找。 其中--save-dev表示开发时依赖。
使用css样式打包,需要用css-loader和style-loader
npm install --save-dev css-loader
css-loader只负责css文件加载,不负责生效。还需要用style-loader将样式添加到dom中,webpack读取loader时,从右往左读取
const path=require('path')
module.exports={
entry:'./src/main.js',
output:{
path:path.resolve(__dirname,'dist'),
filename:'bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}]
}
}
npm install style-loader --save-dev
(node:11068) UnhandledPromiseRejectionWarning: TypeError: this.getResolve is not a function
跟着学习视频看,老师使用的webpack版本是3.6.0,所以对应css-loader的版本是2.0.2,所以卸载重新装一下就好了
npm uninstall css-loader(卸载)
npm install css-loader@2.0.2 --save-dev
使用less样式打包,需要用css-loader和style-loader
npm install --save-dev less-loader less
module.exports = {
...
module: {
rules: [{
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
}]
}]
}
};
使用 url-loader 样式打包,需要用 npm install --save-dev url-loader
npm install --save-dev url-loader
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}] ] } }
如果你仔细阅读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文件,之后npm run build
1.6 webpack中配置Vue
后续项目中,我们会使用Vuejs进行开发,而且会以特殊的文件来组织vue的组件。所以,下面我们来学习一下如何在我们的webpack环境中集成Vuejs,现在,我们希望在项目中使用Vuejs,那么必然需要对其有依赖,所以需要先进行安装注:因为我们后续是在实际项目中也会使用vue的,所以并不是开发时依赖(因此尾部不用加-dev),而且早期引用vue.js不是模块化开发,此处用webpack则是用vue依赖进行模块化开发。相当于去node_modules 找vue,使用的其实是node——modules导出的export 出vue,我们使用它
那么,接下来就可以按照我们之前学习的方式来使用Vue了
初次使用报错如下:
You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
这个错误的问题来源是vue构建发布版本时候,有两种版本
- runtime-only 代码中,不可以有任何的template,因为编译不了组件
- runtime-compiler 代码中,可以有template,因为compiler可以编译组件
我们指定时,参考下面的,则构建不会用默认的,见下下图片
这个错误说的是我们使用的是runtime-only版本的Vue,什么意思,所以我们修改webpack的配置,添加如下内容即可
其实在SPA(单页面复用 sinple page webapplication)开发模式中,经过vue-rooter,因此index.html很少进行修改,在正常运行之后,我们来考虑另外一个问题:
- 如果我们希望将data中的数据显示在界面中,就必须是修改index.html
- 如果我们后面自定义了组件,也必须修改index.html来使用组件
- 但是html模板在之后的开发中,我并不希望手动的来频繁修改,是否可以做到呢?
解决方案:定义template属性:
- 在前面的Vue实例中,我们定义了el属性,用于和index.html中的#app进行绑定,让Vue实例之后可以管理它其中的内容
- 这里,我们可以将div元素中的{{message}}内容删掉,只保留一个基本的id为div的元素
- 但是如果我依然希望在其中显示{{message}}的内容,应该怎么处理呢?
- 我们可以再定义一个template属性,代码如下:
一句话,vue对象中同时有el和template后,则template在解析时,会将el指向的实例进行替换。
终极解决方案-不改html代码,而实现实例替换-抽离出组件化开发
//抽离组件 const cpn={ template:` <div> <h2>{{message}}</h2> <button @click="btnclick">按钮</button> </div> `, data(){ return{ message:'hello webpack' } }, methods:{ btnclick(){ console.log('我爱大中华'); } } } const app=new Vue({ el:'#app', //使用组件 template:`<cpn></cpn>`, data:{ }, components:{ //注册组件 cpn } })
重新打包,运行程序,显示一样的结果和HTML代码结构
那么,el和template模板的关系是什么呢?
- 在我们之前的学习中,我们知道el用于指定Vue要管理的DOM,可以帮助解析其中的指令、事件监听等等。
- 而如果Vue实例中同时指定了template,那么template模板的内容会替换掉挂载的对应el的模板。
这样做有什么好处呢?
- 这样做之后我们就不需要在以后的开发中再次操作index.html,只需要在template中写入对应的标签即可
- 但是,书写template模块非常麻烦怎么办呢?
- 没有关系,稍后我们会将template模板中的内容进行抽离。
- 会分成三部分书写:template、script、style,结构变得非常清晰。
代码修复如下:
ERROR in ./src/main.js
Module not found: Error: Can't resolve 'vue/App.vue' in 'D:\Code\vue\hellworld\05-webpack\src'
@ ./src/main.js 7:11-33
但是一个组件以一个js对象的形式进行组织和使用的时候是非常不方便的
- 一方面编写template模块非常的麻烦
- 另外一方面如果有样式的话,我们写在哪里比较合适呢?
- 现在,我们以一种全新的方式来组织一个vue的组件
但是,这个时候这个文件可以被正确的加载吗?
- 必然不可以,这种特殊的文件以及特殊的格式,必须有人帮助我们处理。
- 谁来处理呢?vue-loader以及vue-template-compiler。
- 安装vue-loader和vue-template-compiler
npm install vue-loader vue-template-compiler --save-dev
修改webpack.config.js的配置文件:
1.7 plugin的使用
plugin是什么?plugin是插件的意思,通常是用于对某个现有的架构进行扩展。webpack中的插件,就是对webpack现有功能的各种扩展,比如打包优化,文件压缩等等。
loader和plugin区别
- loader主要用于转换某些类型的模块,它是一个转换器、加载器。
- plugin是插件,它是对webpack本身的扩展,是一个扩展器。
plugin的使用过程:
- 步骤一:通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
- 步骤二:在webpack.config.js中的plugins中配置插件。
添加版权的Plugin
我们先来使用一个最简单的插件,为打包的文件添加版权声明,该插件名字叫BannerPlugin,属于webpack自带的插件。按照下面的方式来修改webpack.config.js的文件:
重新打包程序:查看bundle.js文件的头部,看到如下信息
如果webpack是4.0以后的,则需要匹配vue-loader 14.0之后的版本
打包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')
js压缩的Plugin
在项目发布之前,我们必然需要对js等文件进行压缩处理,这里,我们就对打包的js文件进行压缩.我们使用一个第三方的插件uglifyjs-webpack-plugin,并且版本号指定1.1.1,和CLI2保持一致
npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
修改webpack.config.js文件,使用插件:
主要做法1是将空格换行去除,2是将变量命名简化调整。
查看打包后的bunlde.js文件,是已经被压缩过了。
搭建本地服务器
webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js搭建,内部使用express框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果。不过它是一个单独的模块,在webpack中使用之前需要先安装它。
npm install --save-dev webpack-dev-server@2.9.1
devserver也是作为webpack中的一个选项,选项本身可以设置如下属性:
- contentBase:为哪一个文件夹提供本地服务,默认是根文件夹,我们这里要填写./dist
- port:端口号,也就是跟在localhost后面端口号,默认8080
- inline:页面实时刷新
- historyApiFallback:在SPA页面中,依赖HTML5的history模式
webpack.config.js文件配置修改如下
在这里需要注意,我们终端执行webpack-dev-server可能失败,因为默认终端在全局找,当然我们可以再配置另外一个scripts:open参数表示直接打开浏览器
package.json的代码
{
"name": "meetwebpack",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"dev": "webpack-dev-server --open"
},
"author": "",
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-preset-es2015": "^6.24.1",
"css-loader": "^2.0.2",
"file-loader": "^4.3.0",
"html-webpack-plugin": "^3.2.0",
"less": "^3.12.2",
"less-loader": "^5.0.0",
"style-loader": "^2.0.0",
"stylus": "^0.54.8",
"stylus-loader": "^4.3.0",
"uglifyjs-webpack-plugin": "^1.1.1",
"url-loader": "^1.1.2",
"vue-loader": "^14.2.2",
"vue-template-compiler": "^2.6.12",
"webpack": "^3.6.0",
"webpack-cli": "^4.2.0",
"webpack-dev-server": "^2.9.1"
},
"dependencies": {
"vue": "^2.6.12"
}
}
webpack-dev-server的配置抽离
开发时需要的配置,例如下面,在实际部署不需要,应该可以抽离出来
devServer:{
contentBase:'./dist',
inline:true
}
编译需要的东西 也进行抽离 new UglifyjsWebpackPlugin()
我们可以考虑在同一文件夹级别,建个build文件夹,内含 base.config.js(公共配置 )、dev.config.js(开发配置)、prod.config.js(生产配置)