# webpacke模块化开发
# 一、为什么要有模块化
# 1】全局变量同名的问题。
其实可以用匿名函数来解决 (function() { })()
但是这个方法的话,代码的复用性就没办法实现。
# 2】代码的编写方式对js文件的依赖顺序几乎是强制性的。
# 3】常见的模块化规范:
CommonJS(node)、AMD、CMD,也有ES6的Modules
# 4】CommonJS(了解在webpack中需要底层支持运行)
①CommonJS的导出
module.exports={
flag:true,
test(a,b){
return a+b
},
demo(a,b){
return a*b
}
}
②CommonJS的导入
//CommonJS模块
let {test,demo,flag}=require('./moduleA.js');
//等同于
let _mA=require('./moduleA.js');
let test=_mA.test;
let demo=_mA.demo;
let flag=_mA.flag;
# 5】ES6的模块化(重要)
①在主html中先模块化所有js文件
...
<script src="aaa.js" type="module"></script>
<script src="bbb.js" type="module"></script>
<script src="ccc.js" type="module"></script>
②再到相应的js文件内导出需要在其他js文件里使用的变量或者函数
//1.导出方式一
name='why',
age=18,
function sum(num1,num2){
return num1+num2
}
export{name,age,sum}
//2.导出方式二
export var name='why'
export var age=18
//3.导出函数或者类
export function sum(num1,num2){
return num1+num2
}
export class person{
run(){
console.log('嘤嘤嘤');
}
}
//4.export default 注意:在同一个模块中不能出现多个
const address='北京市'
export default address //只能导出一个值,导入的时候可以使用不同的名字命名
import add from './xxx.js'
//5.用export default导出一个对象
export default {
const address='成都',
var num=1,
function sum(a,b){
return a*b
}
}
//在导入的时候可以对对象进行随意命名
import xx from './xxx.js'
然后再通过xx.address、xx.num、xx.sum(1,2)来使用变量或者函数
③最后到其他文件里面倒入
//1.基本导入
import {xxx,xxx,xxx} from "./aaa.js"
//2.统一全部导入
import * as xx from './aaa.js'
# 二、Webpack详解
# 1、认识webpack
# 1】webpack模块化的概念:
通过模块化开发完成了项目后,还需要处理模块间的各种依赖,并且将其进行整合打包。而webpack其中一个核心就是让我们可能进行模块化开发,并且会帮助我们处理模块间的依赖关系。而且不仅仅是JavaScript文件,我们的CSS、图片、json文件等等在webpack中都可以被当做模块来使用。
# 2】打包
就是将webpack中的各种资源模块进行打包合并成一个或多个包(bundle)。并且在打包的过程中,还可以对资源进行处理,比如压缩图片,将scss转成css,将ES6语法转成ES5语法,将TypeScript转成JavaScript等等操作。
# 3】grunt/gulp和webpack的不同
①grunt/gulp更加强调的是前端流程的自动化,模块化不是它的核心。
②webpack更加强调模块化开发管理,而文件压缩合并,预处理等功能,是他附带的功能。
# 2、webpack的安装
# ①安装Node.js(Node.js自带了软件包管理工具npm)
# ②可以再cmd中查看node版本(webpack依赖于node.js)
node -v
# ③全局安装webpack(这里我先指定版本号3.6.0,因为vue cli2依赖该版本)
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
# 三、webpack的基本使用过程
①在src中模块化开发
②在终端中:将src中的main.js文件通过webpack打包到dist文件夹下生产bundle.js文件(注意:此操作会将main.js文件中需要的所有依赖文件一起进行打包,如果没有依赖或者使用的文件就不会一起打包的)
webpack ./src/main.js ./dist/bundle.js
③在index.html文件中引用bundle.js,就可以通过webpack的支持实现模块化开发(bundle.js文件就是通过webpack生成的支持模块化的代码)
# 四、webpack的配置
①新建一个命名为webpack.config.js的配置文件
②在这个配置文件中需要导出入口路径和出口路径(绝对路径)
module.exports={
entry:'./src/main.js',
output:{
path:'绝对路径,一般会配合node进行动态管理',
filename:'bundle.js'
}
}
③在终端中输入 webpack 执行命令(全局webpack):将src中的main.js文件通过webpack打包到dist文件夹下生产bundle.js文件(只是一种快速配置)
④package.json中定义启动
如果想要使用npm run xxx 的命令的话,需要在package.json文件中的找到scripts脚本,然后进行插入需要执行的xxx命令名称,然后对其赋值。(注意:package.json中的scripts的脚本在运行时,会按照一定的顺序寻找命令对应的位置。首先会寻找本地的node_modules/bin路径中对应的命令,如果没有找到,会去全局的环境变量中寻找。)
"scripts":{
"dev":"xxxxxx",
"test": "npm run unit && npm run e2e",
"build":"webpack"
}
这里也输入的npm run build 指令,此外此方法会优先地到本地找webpack(局部安装的webpack,可能会造成webpack版本不同的问题),但是直接输入webpack命名就是使用的是全局的(只要在终端里面写命令就是全局的)
# 五、loader
我们之前用webpack来处理写的js代码,并且webpack会自动处理js之间相关的依赖。我们其实也需要加载css、图片,包括一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scss、less转成css,将jsx、.vue文件转成js文件等等。webpack本身是对这些转换是不支持的,现在需要对webpack拓展对应的loader就可以实现了。
# 一】loader使用基本过程:
# ①通过npm安装需要使用的loader
# ②在webpack.config.js中的modules关键字下进行配置
# ③在webpack中文官网中有教程
https://www.webpackjs.com/loaders/
# 二】webpack中使用css文件的配置:(css-loader和style-loader)
css-loader:解析 CSS 文件后,使用import加载,并且返回CSS代码
style-loader:将模块的导出作为样式添加到DOM中
# 1、在main.js中需要依赖css文件
require('./css/xxx.css')
# 2、通过npm安装需要使用的css-loader和style-loader
npm install --save-dev css-loader
npm install style-loader --save-dev
# 3、在webpack.config.js中加一个module对象
module.exports = {
module: {
rules: [
{ //正则表达式:匹配所有的css文件,其中\.是对“.”进行转义,$是结束符
test: /\.css$/,
//css-loader只负责将css文件进行加载,不负责解析
//style-loader负责将样式添加到DOM中
//*重要*:使用多个loader时,是从右向左读取,这里就是先使用style-loader,再使用css-loader
use: ['style-loader','css-loader']
}
]
}
}
# 4、npm run build打包
# 三】webpack中less文件处理(less-loader)
如果我们希望在项目中使用less、scss、stylus来写格式,webpack也可以帮我们进行处理。
# 1、创建一个.less文件
# 2、在main.js中创建依赖
require('./css/xxx.less')
# 3、安装less-loader(对less文件进行加载)和less(把less转化成css过程需要用到的文件)
npm install --save-dev less-loader less
# 4、 在webpack.config.js中添加module对象然后设置如下:
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader','css-loader']
},
{
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
}] //从后往前的顺序进行读取
}
]
}
}
# 四】webpack中图片文件的处理(url-loader和file-loader)
# 1、在项目中导入一张图
# 2、在css中用url的方式引用一张图
# 3、安装url-loader
npm install --save-dev url-loader
# 4、在webpack.config.js中添加module对象然后设置如下:
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader','css-loader']
},
{
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
}] //从后往前的顺序进行读取
},
{
test: /\.(png|jpg|gif)$/,//去匹配不同的格式的图片
use: [
{
loader: 'url-loader',//使用url方式文件的加载
options: {
//**当加载的图片小于limit时,会将图片编译成base64字符串形式
//**如果需要加载的图片大于limit时,会使用file-loader对图片进行加载,file-loader不需要配置,只需要用npm安装就行了
limit: 8192
}
}
]
}
]
}
}
# 5、当加载的图片小于limit时,会将图片编译成base64字符串形式。如果需要加载的图片大于limit时,会使用file-loader对图片进行加载,file-loader不需要配置,只需要用npm安装就行了
npm install --save-dev file-loader
# 6、但是这时候我们会发现此时会在dist中生成一个新的图片文件:生成的文件的文件名就是文件内容的 MD5 哈希值并会保留所引用资源的原始扩展名。
虽然我们现在npm run buile不会报错了,但是网页中还是不能正常显示图片的,我们按F12可以看到源码中URL()里面显示的值是"./哈希值.png",而在我们当前文件夹中是没有这个文件的,所以找不到,这个文件被打包到了dist文件夹下。
此时我们需要在webpack.config.js文件中的找到output对象对他进行添加一个publicPath:'dist/',只要写了这个东西(也就是自定义public发布目录),以后涉及到任何URL的东西,它都会在前面拼接一个dist/
module.exports={
entry:'./src/main.js',
output:{
path:'绝对路径,一般会配合node进行动态管理',
filename:'bundle.js',
publicPath:'dist/'
}
}
# 7、打包之后文件名称的修改
需要在limit后面加name(注意里面的中括号的意思是取原来的名字,所以必须加上,是个变量)
options:{
limit:1000,
name:'img/[name].[hash:8].[ext]'
//img:文件将要要打包到的文件夹
//name:获取图片原来的名字,放在该位置
//hash:8:为了防止图片名称冲突,使用hash,但只保留8位
//ext:使用图片原来的拓展名
}
但是,我们发现图片并没有显示出来,这是因为图片使用的路径不正确
■默认情况下, webpack会将生成的路径直接返回给使用者
■但是,我们整个程序是打包在dist文件夹下的,所以这里我们需要在路径下再添加一个dist/
# 五】ES6语法处理(babel-loader)
需要提高适配性,就需要把ES6语法转成ES5语法
# 1、安装需要用到的babel-loader、babel-core、babel-preset-es2015
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
# 2、配置webpack.config.js文件
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader','css-loader']
},
{
test: /\.less$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "less-loader"
}]
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
},
{
test: /\.js$/,//匹配js文件
//排除文件夹有些js文件没必要弄成es5
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
]
}
}
# 六、使用Vue的配置过程
# 1、我们项目中使用Vuejs,那么必须对其有依赖,所以先进行安装
npm install vue --save
//注意:因为我们后续实在实际项目中也会使用到vue,所以不需要加开发时依赖(-dev)
--save表示运行时依赖
1.1安装vue的三种方式
①直接下载vue.js文件
②CDN引入
③npm安装,依赖被安装到node_modules文件夹下(这个“小写”vue依赖里面,使用export default导出了Vue对象),所以直接用下列代码引用Vue
import Vue from 'vue'
//前面必须是大写的V 后面必须是vue而且没有后缀名
# 2、使用Vue进行开发
import Vue from 'vue'
const app=new Vue({
el:'#app',
data:{
message:'hello webpack'
}
})
# 3、此时打包发布的话,可能无法正常运行,存在以下问题:
在构建发布版本的时候,构建了两类版本:
①runtime-only ->代码中,不可以有任何的template(这个版本就没有包含对template进行编译的代码)
②runtime-compiler ->代码中,可以有template,因为有compiler可以用于编译template
解决方案:我们在webpack.config.js配置文件中添加以下内容
resolve:{
alias:{//alias别名
'vue$':'vue/dist/vue.esm.js'
}
}
# 七、创建Vue时的template和el的关系
SPA(simple page web application) ->vue-router(前端路由)
我们需要尽可能少的修改index.html文件
①index.html中的
就只有
<div id="app"></div>
②在main.js中
# vue实例中如果同事有el和template的话,template会直接把el给替换掉
import Vue from 'vue'
new Vue({
el:'#app',
template:`
<div>
<h2>{{message}}</h2>
</div>
`,
data:{
message:'hello'
}
})
# 八、Vue的终极使用方案(vue-loader)
使用三层结构template,scripts,style格式的.vue文件
# Vue->js->对象->子组件->template->el
# ①如果要加载.vue文件必须要有vue-loader(加载需要)和vue-template-compiler(编译解析需要)
npm install npm install vue-loader vue-template-compiler --save-dev
# ②然后修改webpack.config.js的配置文件
{
test:/\.vue$/,
use:['vue-loader']
}
# ③vue-loader在15.x以上版本需要另外配置一个插件才能使用,否则出错
# 九、plugin插件
# 一】认识plugin:
webpack的plugin插件就是对webpack现有功能的各种扩展,比如打包优化,文件压缩等。
# ①loader和plugin的区别
loader主要用于转换某些类型的模块,它是一个转换器。
plugin是插件,它是对webpack本身的拓展,是一个拓展器。
# ②plugin的使用过程
1】通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
2】在webpack.config.js中的plugins中配置插件
# 二】BannerPlugin的使用(添加版权)
属于是webpack自带的插件
# ①按照下面的方式来修改webpack.config.js的文件
const path=require('path')
const webpack=require('webpack')
module.exports={
...
plugins:[
new webpack.BannerPlugin('最终版权归xxx所有')
]
}
# ②重新打包程序:查看bundle.js文件的头部,看到如下信息:
/*! 最终版权归xxx所有 */
# 三】HtmlWebpackPlugin的使用(打包html)
# 1、意义(非webpack自带的插件)
我们现在的index.html文件是存放在项目的根目录下的,在真实项目中发布的是dist文件夹中的内容,但是dist文件夹中如果没有index.html的话,那么打包的js文件将毫无意义,所以我们需要将index.html打包到dist文件夹下,这个时候就可以使用HtmlWebpackPlugin插件
# 2、使用之后的作用效果
①自动生成一个index.html文件(可以指定模板来生成)
②将打包的js文件,自动通过script标签导入到body中
# 3、安装HtmlWebpackPlugin插件
npm install html-webpack-plugin --save-dev
# 4、使用插件,修改webpack.config.js配置文件中plugins部分的内容如下:
plugins:[
new webpack.BannerPlugin('最终版权归xxx所有'),
new htmlWebpackPlugin({
template:'index.html'
})
]
这里的template表示根据什么模板来生成index.html(它会从webpack.config.js配置文件所在的目录进行查找"index.html")。除此之外,我们还需要删除之前在output中添加的publicPath属性,否则插入的script标签中的src可能会有问题。
# 四】UglifyjsWebpackPlugin的使用(js压缩丑化)
# 1、意义(第三方插件)
发布项目之前我们需要对js文件进行压缩
# 2、安装UglifyjsWebpackPlugin插件
指定版本号1.1.1和cli2保持一致
npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
# 3、修改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()
]
}
# 4、查看打包后的bundle.js,是已经被压缩丑化过了
# 十、搭建本地服务器webpack-dev-server(可以实时监听改变)
webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js搭建,内部使用express框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果。通过把数据暂时保持在内存中来实现,不需要多次npm run build。
在vscode中可以安装live server实现
# 1、需要在webpack使用之前安装它:
npm install --save-dev webpack-dev-server@2.9.1
# 2、devServer也是作为webpack中的一个选项,选项本身可以设置如下属性:
# ■contentBase:
为哪一个文件夹提供本地服务,默认是根文件夹,我们这里需要填写./dist
# ■port:
端口号
# ■inline:
页面实时刷新
# ■historyApiFallback:
在SPA页面中,依赖HTML5的history模式
# 3、webpack.config.js文件配置修改如下:
devServer:{
contentBase:'./dist',
inline:true
}
# 4、此时输入webpack-dev-server是不行的,因为刚才操作的是局部安装,终端中是全局查找的,我们还需要在package.json文件配置另外一个scripts:
"dev":"webpack-dev-server --open"
//--open参数表示直接打开浏览器
# 5、此时输入npm run dev就行了,而且改变了代码的话,刷新浏览器就可以看到变化。
# 十一、webpack-merge的使用(配置文件的分离)
开发需要用到的config配置文件和发布时需要用到的config配置文件进行分离。
# 1、分类建文件base.config.js(基本),prod.config.js(发布时),dev.config.js(开发时)将webpack.config.js的内容抽离
# 2、安装webpack-merge(合并的意思)
npm install webpack-merge --save-dev
# 3、在pro.config.js中修改为
const webpackMerge=require('webpack-merge')
const baseConfig=require('./base.config')
module.exports=webpackMerge(baseConfig,{
plugins:[...]//抽离出来的内容
})
# 4、在dev.config.js中同上方法修改为
const webpackMerge=require('webpack-merge')
const baseConfig=require('./base.config')
module.exports=webpackMerge(baseConfig,{
...//抽离出来的内容
})
# 5、现在终端执行npm run build是会报错的,还需要对在package.json中对build进行修改
"build":"webpack --config ./build/prod.config.js",
"dev":"webpack-dev-server --open --config ./build/dev.config.js"
//手动用--config进行指令需要找的文件名,否则webpack只会去找文件名为webpack.config.js的文件