vue面试常见问题整理
一指令解释:指令(Directives)是带有v-前缀的特殊属性作用:当表达式的值改变时,将其产生的连带影响,响应式地作用于DOMv-text解释:更新元素的textContent<h1v-text="msg"></h1>v-html解释:更新元素的innerHTML...
一 指令
- 解释:指令 (Directives) 是带有 v- 前缀的特殊属性
- 作用:当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
v-text
- 解释:更新元素的 textContent
<h1 v-text="msg"></h1>
v-html
- 解释:更新元素的 innerHTML
<h1 v-html="msg"></h1>
v-bind
- 作用:当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM
- 语法:v-bind:title="msg"
- 简写::title="msg"
v-on
- 作用:绑定事件
- 语法:v-on:click="say" or v-on:click="say('参数', $event)"
- 简写:@click="say"
- 说明:绑定的事件从methods中获取
事件修饰符
- .stop 阻止冒泡,调用 event.stopPropagation()
- .prevent 阻止默认事件,调用 event.preventDefault()
- .capture 添加事件侦听器时使用事件捕获模式
- .self 只当事件在该元素本身(比如不是子元素)触发时触发回调
- .once 事件只触发一次
v-model
- 作用:在表单元素上创建双向数据绑定
- 说明:监听用户的输入事件以更新数据
v-for
- 作用:基于源数据多次渲染元素或模板块
key属性
- 推荐:使用 v-for 的时候提供 key 属性,以获得性能提升。
- 说明:使用 key,VUE会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
样式处理 -class和style
- 说明:这两个都是HTML元素的属性,使用v-bind,只需要通过表达式计算出字符串结果即可
- 表达式的类型:字符串、数组、对象
- 语法:
<!-- 1 --> <div v-bind:class="{ active: true }"></div> ===> <div class="active"></div>
v-if 和 v-show
- 条件渲染
- v-if:根据表达式的值的真假条件,销毁或重建元素
- v-show:根据表达式之真假值,切换元素的 display CSS 属性
不同点:
1 . v-if 当值为 true时,显示div ,
当值为false时,改元素消失,代码也会消失,
相当于将代码删除了,当在为true时,页面会重新渲染div;
支持加在<template>标签上
而v-show 控制的隐藏出现,
只是将css属性设为了display:none 或block;
不支持加在<template>标签上
2.v-if 后还有 v-else 和 v-else-if 条件渲染,
这里需要注意的是v-else 必须紧跟 v-if 或v-else-if
3.v-if是真真正正的条件渲染;
然而他是惰性的,
在初始值是false的时候,他就什么都不做,
在为真的时候才会开始局部变异
相比之下v-show则是更简单一下,仅仅是css上的切换
所以,v-if有更高的切换消耗,
而v-show有更高的初始渲染消耗;
因此,如果是频繁切换,就用v-show;
在条件很难改变,比如某个模块在用户a出显示,就用v-if
提升用户体验:v-cloak
- 这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。
- 防止刷新页面,网速慢的情况下出现{{ message }}等数据格式
<div v-cloak> {{ message }} </div>
提升性能:v-pre
- 说明:跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
<span v-pre>{{ this will not be compiled }}</span>
提升性能:v-once
- 说明:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。
<span v-once>This will never change: {{msg}}</span>
二.组件
全局
全局组件注册方式:Vue.component(组件名,{方法})
注意:
全局组件必须写在Vue实例创建之前,才在该根元素下面生效;
模板里面第一级只能有一个标签,不能并行;
data里面this指的是window,在methods里面this才是Vue实例
局部
局部组件注册方式,直接在Vue实例里面注册
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
注意:
属性名为components,s千万别忘了;
data里面this指的是window,在methods里面this才是Vue实例
组件的属性以及用法和意义
data:data必须是一个函数 返回一个唯一的对象,不要和其他组件共用一个对象进行返回!!!每一个实例的data属性都是独立的,不会相互影响了
watch
首先确认 watch是一个对象,一定要当成对象来用。
对象就有键,有值。
键:就是你要监控的那个家伙,比如说$route,这个就是要监控路由的变化。或者是 data中的某个变量。
值可以是函数:就是当你监控的家伙变化时,需要执行的函数,这个函数有两个形 参,第一个是当前值,第二个是变化后的值。
值也可以是函数名:不过这个函数名要用单引号来包裹。
第三种情况厉害了。
值是包括选项的对象:选项包括有三个。
第一个handler:其值是一个回调函数。即监听到变化时应该执行的函数。
- 第二个是deep:其值是true或false;确认是否深入监听。(一般监听时是不能监听到对象属性值的变化的,数组的值变化可以听到。)
- 第三个是immediate:其值是true或false;确认是否以当前的初始值执行handler的函数。
computed
做筛选功能,与watch的用法相似,也是键值,键就是data里面的数据名称,值是一个函 数,用来操作步骤。
组件的生命周期
生命周期钩子 | 组件状态 | 最佳实践 |
beforeCreate | 实例初始化之后,this指向创建的实例,不能访问到data、computed、watch、methods上的方法和数据 | 常用于初始化非响应式变量 |
created | 实例创建完成,可访问data、computed、watch、methods上的方法和数据,未挂载到DOM,不能访问到$el属性,$ref属性内容为空数组 | 常用于简单的ajax请求,页面的初始化 |
beforeMount | 在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数 | – |
mounted | 实例挂载到DOM上,此时可以通过DOM API获取到DOM节点,$ref属性可以访问 | 常用于获取VNode信息和操作,ajax请求 |
beforeupdate | 响应式数据更新时调用,发生在虚拟DOM打补丁之前 | 适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器 |
updated | 虚拟 DOM 重新渲染和打补丁之后调用,组件DOM已经更新,可执行依赖于DOM的操作 | 避免在这个钩子函数中操作数据,可能陷入死循环 |
beforeDestroy | 实例销毁之前调用。这一步,实例仍然完全可用,this仍能获取到实例 | 常用于销毁定时器、解绑全局事件、销毁插件对象等操作 |
destroyed | 实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁 | – |
注意:
- created阶段的ajax请求与mounted请求的区别:前者页面视图未出现,如果请求信息过多,页面会长时间处于白屏状态
- mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染
完毕,可以用 vm.$nextTick
- vue2.0之后主动调用$destroy()不会移除dom节点,作者不推荐直接destroy这种做法,如果实在需要这样用可以在这个生命周期钩子中手动移除dom节点
组件通讯
父组件给子组件传值
传 父组件用:变量名:"变量值"
接 在子组件中定义props属性
props:{
变量名:变量的类型
}
用 在模板里{{变量名}}即可等到传过来的值
子组件给父组件传值
传 在子组件定义一个事件如@click="add"
然后 在methods中设置
methods: {
add() {
用 this.$emit触发在父组件中定义好的自定义事件(例子中的increment)
name是子组件要传给父组件的值
this.$emit('increment',this.name)
}
}
接 在父组件中定义好的子组件的标签上定义
increment就是自定义事件,子组件就是触发的这个事件
incrementTotal是触发自定义事件后发生的函数方法
<Zi @increment="incrementTotal"></Zi>
methods: {
incrementTotal (name) {
name就是子组件传过来的值,只要将他赋值给data里的变量,就可以在模板使用了
console.log(name)
}
}
用 在模板里{{变量名}}即可等到传过来的值
非父子通信
简单情况下我们可以通过使用一个空的Vue实例作为中央事件总线
在main.js文件夹下建一个vue空实例
let bus = new Vue()
Vue.prototype.bus = bus
在一个组件中定义this.bus.$emit('toChangeTitle','从首页来')
toChangeTitle自定义事件名称,后面是要传的值
在另一个组件中的接收
mounted () {
this.bus.$on('toChangeTitle', function (title) {
toChangeTitle //前一个组件定义的自定义事件名
title //值 把他赋值给data里的变量就可以在模板中使用了
console.log(title)
})
}
dom操作
vue提供的ref属性以及this.$refs即可实现
$refs
首先你的给子组件做标记。demo :<firstchild ref="one"></firstchild>
然后在父组件中,通过this.$refs.one就可以访问了这个自组件了,包括访问自组件的data里面的数据,调用它的函数
2)$children
他返回的是一个组件集合,如果你能清楚的知道子组件的顺序,你也可以使用下标来操作;
1 2 3 | for(let i=0;i<this.$children.length;i++){ console.log(this.$children[i].msg);输出子组件的msg数据; } |
2)$parent 与$children相似
路由
vue-router是专门针对于vue提供单页面路由创建的插件
什么单页面应用?
只有一个页面的应用,但是可以有多个路由地址。正常情况下只要是a链接,点击后都会向服务端发起请求
而单页面应用,
只有在第一次访问的时候,或者强制刷新的时候会向服务端发起请求,其他情况则不会
这是由于单页面路由利用前端页面的几个特性
1,hash
hash可以改变url地址不会向后端发出请求,而且留有历史纪录,通过hashchang事件可以监听hash的改变
2,history
html5针对history api新增了,pushState, replaceState 方法进行url地址的改变,并且不会向服务端发起请求
新增了popstate事件监听url通过历史纪录,pushstate,replaceState方法改变url的监听
单页面应用的特点
改变url地址,
不会像后端发起请求,并且可以重新渲染页面,达到页面异步更新的效果,
而且会留有历史纪录
在vue中结合history,hash实现了路由跳转的封装,封装成了统一的跳转方法,统一的监听处理,
同vue实例中mode选型可以对两种模式进行切换
什么是路由?
路由的概念本身是后端,后端通过定义路由,指定渲染的页面,浏览器通过url地址访问,服务端接收到请求,给客户端返回需要渲染的内容
一个url地址
vue-router如何使用
1,下载vue-router并且引入 import VueRouter from 'vue-router'
2,注册vue-router vue.use(VueRouter)
3, 实例化vue-router new VueRouter(配置)
4, 对实例进行配置
配置选项:
{
mode: 'hash', // hash || history
router: [
{
path: '', //路由地址 /user
compoent: '', 路由对应需要渲染的组件,渲染到router-view对应的位置
name: '', 指定路由名称
meta: {}, 路由的其他配置参数可以是如何数据
redirect: '', 重定向
children: [
{
path: 'home' // /user/home
},
{
path: '/home' // /home
}
], //对应的子路由
}
], // 所有路由列表, 每一项是一个路由规则
}
5, router-view 指定路由对应渲染的位置
6, 将router实例挂载到vue根实例上,在组件中就可以使用$router访问到router实例了
7,路由的跳转控制
使用组件router-link
使用js方法 $router.push()
$router.replace()
back()
go() ....
8, 路由的拦截
$router和$route的关系
$route为当前router跳转对象里面可以获取name、path、query、params等
$router为VueRouter实例,想要导航到不同URL,则使用$router.push方法等
<router-link>中的to 和 :to 的区别
to是指直接跳转页面 <router-link to="aa>go</router-link">
:to是指跳转时候传参<router-link :to="{path:'tt',query:{'cc':'cc'}}">go </router-link>
路由传参
params传参 <router-link :to="{name:'go',params:{'cc':'this is cc'}}">
query传参 <router-link :to="{name:'go',query:{'cc':'this is cc'}}">
1、用法上的
刚才已经说了,query要用path或者name都可以引入,params要只用用name来引入,接收参数都是类似的,分别是this.$route.query.name和this.$route.params.name。
注意接收参数的时候,已经是$route而不是$router了哦!!
2、展示上的
query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
3.调用方面
params一旦传参就必须调用,e而query,定以后可调可不调用
因为params是路由的一部分,必须要有。query是拼接在url后面的参数,没有也没关系
4.使用场景
params:/router1/:id ,/router1/123,/router1/789 ,这里的id叫做params
query:/router1?id=123 ,/router1?id=456 ,这里的id叫做query。
响应路由参数的变化
提醒一下,当使用路由参数时,例如从 /user/foo 导航到 user/bar,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch(监测变化) $route 对象:
命名视图
有时同时(候想同级)展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar(侧导航) 和 main(主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。
<router-view class="view one"></router-view> <router-view class="view two" name="a"></router-view> <router-view class="view three" name="b"></router-view>
一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置(带上 s):
const router = new VueRouter({ routes: [ { path: '/', components: { default: Foo, a: Bar, b: Baz } } ] })
重定向
重定向也是通过 routes 配置来完成,下面例子是从 /a 重定向到 /b:
const router = new VueRouter({ routes: [ { path: '/a', redirect: '/b' } ] })
重定向的目标也可以是一个命名的路由:
const router = new VueRouter({ routes: [ { path: '/a', redirect: { name: 'foo' }} ] })
甚至是一个方法,动态返回重定向目标:
const router = new VueRouter({ routes: [ { path: '/a', redirect: to => { // 方法接收 目标路由 作为参数 // return 重定向的 字符串路径/路径对象 }} ] })
别名
『重定向』的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b,那么『别名』又是什么呢?
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。
上面对应的路由配置为:
const router = new VueRouter({ routes: [ { path: '/a', component: A, alias: '/b' } ] })
『别名』的功能让你可以自由地将 UI 结构映射到任意的 URL,而不是受限于配置的嵌套路由结构。
导航钩子
vue-router 提供的导航钩子主要用来拦截导航,让它完成跳转或取消。有多种方式可以在路由导航发生时执行钩子:全局的, 单个路由独享的, 或者组件级的。
- 全局钩子
const router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // do something next(); }); router.afterEach((to, from, next) => { console.log(to.path); });
每个钩子方法接收三个参数:
- to: Route : 即将要进入的目标 [路由对象]
- from: Route : 当前导航正要离开的路由
- next: Function : 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next方法的调用参数。
next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是confirmed (确认的)。
next(false): 中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from路由对应的地址。
next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
确保要调用 next方法,否则钩子就不会被 resolved。
- 组件内的钩子
你可以在路由组件内直接定义以下路由导航钩子:
beforeRouteEnter beforeRouteUpdate (2.2 新增) beforeRouteLeave
const Foo = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当钩子执行前,组件实例还没被创建 }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` } }
beforeRouteEnter 钩子 不能 访问 this,因为钩子在导航确认前被调用,因此即将登场的新组件还没被创建。
不过,你可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
beforeRouteEnter (to, from, next) { next(vm => { // 通过 `vm` 访问组件实例 }) }
你可以 在 beforeRouteLeave 中直接访问 this。这个 leave 钩子通常用来禁止用户在还未保存修改前突然离开。可以通过 next(false) 来取消导航。
vuex
原理:
vuex的方案是,在vue中构建一个用于存储state、定义操作state方法的仓库(即store)。通过在多个(不一定是全部)组件中引用需要的state、调用“操作state的方法”来实现对给共享变量的处理。且由于各个组件对state是引用的,单个组件改变了某个state后,其他组件可以实时的响应变化。
使用
1.下包
cnpm install --save-dev vuex
2.在项目src目录下创建vuex文件夹,再里创建store.js文件
3.在store.js中
引入vue和vuex
import Vue from 'vue'
mport Vuex from 'vuex'
在入口文件引入vuex并将store添加到根结点上
4.store.js中的基本结构是
import Vue from 'vue'
mport Vuex from 'vuex'
Vue.use(Vuex)
const state = { //状态 在视图里面渲染的基本都放在state里
list:[],
num:0
//存放共享组件
}
const getters = { //计算过滤操作
state中的变量:(state)=>{
return state.变量名+一些列的操作
}
}
const mutation = { //同步改变状态
add(state){
state.num++
}
//可以放一些改变state的方法
}
const actions ={ //异步改变状态 在视图中调用actions里的方法一般使用
this,$store.dispatch('方法名')
方法名(context){ //这里的context是一个上下文对象 相当于当前的store 也可以直接
使用{commit}
context.commit('调用mutation里的方法',自由参数)
}
}
export default new Vuex.store({
state,
mutations,
actions,
getters,
})
视图应用
如果想把state里的数据映射在视图中,如liste:[]需要以下操作
第一种:可以直接在组件中{{this.$store.state.list}} //注意list是个数组需要循环
第二种 可以在视图中引入mapState方法
import {mapState} from 'Vuex'
然后在视图计算属性中
computed:{
...mapState(['list']) //es6的扩展符
}
然后在组件中直接使用 {{list}} //注意list是个数组需要循环
如果想把mutation里的方法想应用在视图中,如add需要以下操作
第一种:可以直接在组件中事件的函数中“this.$store.commit("add",自由参)”
第二种 可以在视图中引入mapMutation方法
import {mapMutation} from 'Vuex'
然后在视图的方法中
methods:{
...mapMutation(['add'])
}
可以直接在组件中事件的函数中"add",自由参
actions的应用与mutation类似
getters的应用就是把state引进修改后return出去就好
vuex与全局变量的区别
vuex响应vue的规则 全局变量
vuex实现的作用:数据共享机制
通过统一的数据中心store维护状态数据,每个组件进行更新的时候,通知数据中心 store。再由stroe将共享的状态,触发每一个调用它的组件的更新。
vuex的工作流程
1.在vue组件里面,通过dispatch来触发actions提交修改数据的操作。
2.然后再通过actions的commit来触发mutations来修改数据。
3.mutations接收到commit的请求,就会自动通过Mutate来修改state(数据中心里面的数据状态)里面的数据。
4.最后由store触发每一个调用它的组件的更新
vuex
什么是状态?
当前样子,可以发生变化,开始的状态,结束的状态。
什么是状态管理?
让状态以一定形式定义,一定的形式改变,一定的形式获取,提供一个规则
Vuex 是什么?
是专门针对vue提供的状态管理模式。
它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能
为什么要用vuex?
为了更好的管理状态,在之前组件内部状态的应用中发现,每个组件的状态都是独立的,如果存在好多组件公用的状态通讯起来比较麻烦
vuex的出现,他是将所有数据状态集中式存储管理,变成了一个,在组件中以相应的规则去读取改变。
有什么能够替代vuex,但是为什么不用?
可以使用redux或者将数据定义在vue根实例中,或者定义全局变量
redux:他并不是针对vue专门做处理的,无法同步状态和视图之间的转换
vue根实例:因为vue根实例的定义是整个应用程序,而不是数据管理
全局变量:var store = {}, 没有规则,无法同步状态和视图之间的转换
vuex:专门针对vue开发的一套以集中式的存储管理整个状态树,并且以对应的规则进行数据的管理,而且还兼容vue的数据检测
vuex的核心概念
state: 唯一数据源, 定义在store中的state选项,在组件中可以通过this.$store.state读取,一半都写在计算属性中,可以通过mapState()函数生成计算属性
getters:相当于组件中的计算属性, 定义在store中getters选项中,在组件中通过$store.getters获取,一半都写在计算属性中,可以通过mapGetters()函数生成计算属性
getters: {
计算属性名称 (state, getters) => {
return 返回值
}
}
mutation: 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,
并且它会接受 state 作为第一个参数, 其他参数为第二个, 通过commit可以执行他
注意:Mutation 必须是同步函数
因为mutation中除了改变state之外还将state改变的过程快照记录了下来,如果在mutation中写异步逻辑的话就无法记录快照了
actions: 用来提交mutations,可以处理异步逻辑,但是不能直接修改state,只能通过commit('mutation')的形式改变state,actions函数接收一个context对象(类似于store实例)
1,webpack打包的配置,常见的loaders和plugins?
2,webpack的基本配置有哪些?
Entry 配置模块的入口;
Output 配置如何输出最终想要的代码;
Module 配置处理模块的规则;
Resolve 配置寻找模块的规则;
Plugins 配置扩展插件;
DevServer 配置 DevServer;
3,webpack 打包按需加载?
在 webpack 的构建环境中,要按需加载代码模块很简单,遵循 ES 标准的动态加载语法 dynamic-import 来编写代码即可,webpack 会自动处理使用该语法编写的模块:
需要我们在 webpack 配置中添加一个 output.chunkFilename 的配置:
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[hash:8].js',
chunkFilename: '[name].[hash:8].js' // 指定分离出来的代码文件的名称
}
3,简单介绍下webpack的工作原理?
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
确定入口:根据配置中的 entry 找出所有的入口文件;
编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
https://whjin.github.io/full-stack-development/posts/工作原理概括.html
4,webpack配置开发环境和生产环境的区别?
日常的前端开发工作中,一般都会有两套构建环境:一套开发时使用,构建结果用于本地开发调试,不进行代码压缩,打印 debug 信息,包含 sourcemap 文件;另外一套构建后的结果是直接应用于线上的,即代码都是压缩后,运行时不打印 debug 信息,静态文件不包括 sourcemap 的。有的时候可能还需要多一套测试环境,在运行时直接进行请求 mock 等工作。
webpack 4.x版本在webpack配置中有mode选项可以直接配置production 或 development
webpack 3.x 一般是通过node命令传递环境变量,来控制不同环境下的构建行为
如:
{
"scripts": {
"build": "NODE_ENV=production webpack",
"dev": "NODE_ENV=development webpack-dev-server"
}
}
然后在 webpack.config.js 文件中可以通过 process.env.NODE_ENV 来获取命令传入的环境变量:
更多推荐
所有评论(0)