Vue+Webpack打造todo应用

一、课程介绍

课程地址:https://www.imooc.com/learn/935

1.概要

19171b10962bd415c84db5301c8cc8f13f2.jpg

033599f143b08a2ded62180fc5acd8c5950.jpg

fe3a1e353975da68494e1ee0d086d42801c.jpg

2.vue-loader+webpack项目配置

6595a60b191539ea9ec5e69ec8afca6cd8b.jpg

86416fd30e086d5f689aeaf5dd67ea90472.jpg

895d3803aa2cc13f4527d4585772596ceb3.jpg

安装vs-code和插件

EditorConfig for VS Code
ESLint
gitignore
language-stylus
Nunjucks
One Dark Pro
PostCSS syntax
Vetur
View In Browser
vscode-icons

2e861afbabc0a764ffe016f90638ca38767.jpg

软件配置

{
    "window.zoomLevel": 2,
    "editor.fontSize": 20,
    "workbench.iconTheme": "vscode-icons",
    "files.autoSave": "onFocusChange",
    "terminal.integrated.fontSize": 20,
    "editor.tabSize": 2
}

打开命令行:ctrl+~

初始化项目

npm init

17811192b23b46e8f962d2eb7c0043ce4a2.jpg

安装

npm i webpack@^3.10.0 vue vue-loader@^13.6.0

注意:

A.webpack需要安装到4版本以下

B.vue-loader需要安装15版本以下(参考官方文档 https://vue-loader.vuejs.org/migrating.html#a-plugin-is-now-required . Vue-loader在15.*之后的版本都是 vue-loader的使用都是需要伴生 VueLoaderPlugin的)

79b4a4b77ff2576ec4e5fad2808576e8120.jpg

安装警告依赖

npm i css-loader vue-template-compiler

829374027ffc3edda6009db81017d947e24.jpg

8e786299a73fc353df83ac42c7cf23f36d3.jpg

初始化好了

8576d250065f91ac30d4644b436ae7e94f4.jpg

新建src/app.vue

<template>
    <div id="test">{{text}}</div>
</template>
<script>
export default {
    data(){
        return{
            text:'abc'
        }
    }
}
</script>
<style>
#test{color: red}
</style>

ae88c3aba790cb1af8587c3489f5edf4d80.jpg

9b211b6e828f7cb52776add63e3fae59069.jpg

084879e7701a638076115f753596a3d5fe7.jpg

f723249a4bdb6e68d355f5522926335238f.jpg

添加脚本

index.js

import Vue from 'vue'
import App from './app.vue'

const root = document.createElement('div')

document.body.appendChild(root)

new Vue({
  render:(h) => h(App)
}).$mount(root)

 webpack.config.js

"build": "webpack --config webpack.config.js"

执行打包命令 

npm run build

b105176ff909db717099cece98fc58fafc4.jpg

生成dist文件夹

红色报错,说明没有编译器解释

bec4a9c0c2332be953a5f215ab77817c9cb.jpg

npm run build

8bf5d3714102ae6cfc37a53fd1dbbe0cb67.jpg

515dca088a9d09d9a33ad4e5ae8e5f342d5.jpg

3. webpack配置项目加载各种静态资源及css预处理器

2a23f07a95238ba27032f1fff2804befe20.jpg

npm i style-loader url-loader file-loader

url-loader是建立在file-loader基础上的,base64,。

limit对文件大小做限制。

use不仅是读取,还包括做的一些处理。

[name]原文件名,[ext]扩展名

7c91dcbab1c2d795ef168738c20fa1454b2.jpg

如运行还有其他报错,可参考上图给安装依赖版本

9ea70280f46967370660109c9db0360acfd.jpg

26bedb582089b57b91a87cb0f2e9b873e04.jpg

npm run build

d223cebd3b3430ae2f3a41e0532ce5f5e70.jpg

ad2f782d6e89953942ad559b55a5a7bcb26.jpg

eb04b4fe8006a3cecd9c785404ca24fcc42.jpg

88197cc92e959dfbf8a0cf200f2a83b8ffe.jpg

新建styles/test-stylus.styl样式文件,写法很随意,可以不要大括号和冒号等

10a6ee31f960f2fb993edbaa2c9bee02267.jpg

npm run build

048a106d9da8726b6536bc96387b3ff7c2b.jpg

需要安装stylus-loader

npm i stylus-loader stylus

7a4d60115cd3db777f4bee64efc8e73f804.jpg

cd512de89a2633cf8e9e0603822d1b8b100.jpg

4.webpack-dev-server的配置使用

安装

npm i webpack-dev-server@^2.9.7

这个版本应该与webpack版本相互兼容,3.1.5版本会报错,推测要在3以下

df4b5586ec8f1ec0f692bd202b33c395c45.jpg

针对不同平台的依赖

npm i cross-env

dc6e816b8c9d71790573f1e50cd63af6933.jpg

说明:mac上不需要用set,windows上需要

6841753112ef1fdf4662afc771181ed8c1f.jpg

b0d3f03e0fa56dae7b70fc2f645e520f1db.jpg

5da9452bb77b87afcc5f0a46191d44ddc01.jpg

配置好dev

引入html的插件

安装

npm i html-webpack-plugin

795c6ec2d84f1be60f441563809e06274eb.jpg

e29297e0645e61b529e8af246b718116c07.jpg

配置

bc242cefe0f69e5677d0712b69d7022d9bb.jpg

be9f10b0dce0c4763c62e08f506d9eb7e02.jpg

使用插件,在js中可以直接引用环境判断,vue可以根据不同环境打包,开发环境会有很多错误提示,但是正式环境不需要

npm run dev

19f5ff859ad354c8b2e284cdd6073171f9d.jpg

打开查看

eb9f45d1ea1e5e17d225477a7fb0593aad2.jpg

设置热加载

package.js(部分)

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
    "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"
  },

webpack.config.js

const path = require('path')

const HTMLPlugin = require('html-webpack-plugin')
const webpack = require('webpack')

const isDev = process.env.NODE_ENV === 'development'

const config = {
  target: 'web',
  entry:path.join(__dirname,'src/index.js'),
  output: {
    filename: 'bundle.js',
    path: path.join(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      },
      {
        test: /\.styl/,
        use: [
          'style-loader',
          'css-loader',
          'stylus-loader'
        ]
      },

      {
        test: /\.(gif|jpg|jepg|png|svg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 1024,
              name: '[name]-aaa.[ext]'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: isDev ? '"development"' : '"production"'
      }
    }),
    new HTMLPlugin()
  ]
}

if (isDev) {
  config.devtool = '#cheap-module-eval-source-map' // 浏览器打开后,通过映射以编译后我们能看懂方式调整,source-map最完整映射关系,但是编译效率比较低,文件比较大,eval可能看起来会比较乱,出现行对应不齐的问题。而推荐的这个效率比较高
  config.devServer = {
    port: 8000,
    host: '0.0.0.0',
    overlay: {
      errors: true,
    },
    hot: true // 改了一个组件的代码,只重新渲染这个组件,不贵整个页面渲染
    // historyFallback: {

    // }// 入口地址映射,(略)
    // open: true //启动后自动打开页面
  },
  config.plugins.push(
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin() // 不需要信息展示的问题
  )
}

module.exports = config

二、vue2介绍和项目实践

1.vue2的核心知识介绍

11e275e706b0d024b0c023cbe82404fe214.jpg

c2838802d509dc9e820c236aab36910dada.jpg

2.配置vue的jsx写法以及postcss

安装插件

npm i postcss-loader autoprefixer babel-loader babel-core

c2fd146cad29257c6dd7833eecce6aa82f8.jpg

项目文件夹下创建babelrc和postcss.config.js配置文件

f44c5d4edf741a08be9f4723cecf1f716a7.jpg

postcss是在css文件都编译完之后,通过autoprefixer对其优化,需要加入浏览器前缀支持的

c89d837c5f65f0557724ec4ee3164ad7568.jpg

将vue-jsx文件的转化

npm i babel-preset-env babel-plugin-transform-vue-jsx

安装依赖

d9378bf231283b174265ca5d80b85fca5bd.jpg

编译处理

b1c6273c37e45333275dbd5f637c8c36543.jpg

更快一些

e140ce30d9c2d4fc9cb2b563c17688bc22e.jpg

npm i babel-helper-vue-jsx-merge-props@^2.0.0 css-loader@^0.28.7 babel-plugin-syntax-jsx
npm run dev

打包没报错即可

3. 实现todo应用的界面

700b19db8469d62990a22db851dd5420dff.jpg

f188da387f3ecaf71e239b2f4ed75edd6d5.jpg

调整assets文件夹到src下

179b8ceb67c0b21dc74b40fc3424d63dee9.jpg

删除之前测试使用的

0aef6d32d0687fa4370953fb9076c407f48.jpg

新建src/todo及其以下文件

b6fbca4f0e3fffb4dfc68fc751e51b384e1.jpg

新建assets/styles/globel.styl文件

bbd247fa92ebd557100305b852f22d15d10.jpg

引入

样式内容略,删除app.vue的内容

e51358c0a13552cda64d53e5d7ff23530b2.jpg

样式具体内容略。lang指定预处理器,scoped仅仅对本组件作用

(1)基本组件的引用,样式

header.vue

<template>
  <header class="main-header">
    <h1>Todo</h1>
  </header>
</template>
<style lang = 'stylus' scoped>
.main-header{
  text-align center
  h1{
    font-size 100px
    color rgba(175,47,47,0.6)
    font-weight 500
    margin 20px
  }
}
</style>

todo.vue

<template>
  <section class="real-app">
    <input 
      type="text"
      class="add-input"
      autofocus='autofocus'
      placeholder="接下来要做什么"
      @keyup.enter="addTodo"
    >
    <item :todo='todo'></item>
    <!-- @keyup 也就等于 v-on:keyup -->
    <tabs :filter = 'filter'></tabs>
  </section>
</template>
<script>
import Item from './item.vue'
import Tabs from './tabs.vue'
export default {
  data() {
    return{
      todo:{
        id:0,
        content:'this is todo',
        completed: false
      },
      filter:'all'
    }
  },
  methods: {
    addTodo(){

    }
  },
  components: {
    Item,Tabs
  }
}
</script>
<style lang=stylus scoped>
.real-app{
  width 70%
  min-width 500px
  padding 10px
  background #ffffff
  color #555555
  margin 20px auto
  box-shadow 0 0 10px 5px rgba(0,0,0,0.5)
  .add-input{
    width 84%
    font-size 24px
    border none
    margin 0 6%
    padding 20px 2%
    outline none
    border-bottom 1px solid #fff
  }
  .add-input:hover{
    color #333
    border-bottom 1px solid #ccc
    cursor pointer
  }
}
</style>

tabs.vue

<template>
  <div class="helper">
    <span class="left">2 items left</span>
    <span class="tabs">
      <span
        v-for="state in states"
        :key="state"
        :class="[state, filter === state ? 'actived' : '']"
        @click="toggleFilter(state)"
      >
        {{state}}
      </span>
    </span>
    <span class="clear" @click="clearAllCompleted" type='button'>
      Clear Completed
    </span>
  </div>
</template>

<script>
export default {
  props: {
    filter: {
      type: String,
      required: true
    }
  },
  data(){
    return{
      states:['all', 'active','completed']
    }
  },
  methods: {
    clearAllCompleted (){},
    toggleFilter(){}
  }
}
</script>
<style lang="stylus" scoped>
.helper{
  text-align center
  .left{width:18%;display inline-block}
  .tabs{
    width 50%
    display inline-block
    margin 10px auto
    span{
      min-width 33%
      display inline-block 
      }
    span:hover{
      cursor pointer
      color orange
    }
    span.actived{
      color red
      }
    }
  .clear{ 
    width 30%
    display inline-block 
    color:grey
    border none
    outline none
    }
  .clear:hover{
    color black
    cursor pointer
    }
  input[type='button']{
    border-width 0
  }
}
</style>

item.vue

<template>
  <div :class="['todo-item',todo.completed ? 'completed' : '']">
    <input 
      type="checkbox"
      class="toggle"
      v-model="todo.completed"
    >
    <label>{{todo.content}}</label>
    <button class="destory" @click="deleteTodo"></button>
  </div>
</template>
<script>
export default {
  props:{
    todo:{
      type:Object,
      required:true
    }
  },
  methods:{
    deleteTodo(){

    }
  }
}
</script>

<style lang=stylus scoped>
.todo-item{
  vertical-align text-top
  border none
  padding 15px 2%
  width 88%
  margin 10px 4%
  border-bottom 1px solid #eee
  font-size 28px
  input[type="checkbox"],input[type="checkbox"]:checked{
    vertical-align text-top
    width 30px
    height 30px
  }
  .destory{
    width 30px
    height 30px
    float  right
  }
}
</style>

footer.jsx

import '../assets/styles/footer.styl'
export default {
  data() {
    return {
      author: 'Jhon'
    }
  },
  render(){
    return (
      <div id="footer">
        <span>written by {this.author}</span>
      </div>
    )
  }
}

footer.styl

#footer
  background:rgba(0,0,0,0.2)
  text-align: center
  margin-top: 50px

global.styl

body
  background-image: url('../images/bg.jpg')

7d756b1eface3a03309a13770a96b4562f4.jpg

4.实现todo应用的业务逻辑

(1)添加和删除操作

9ab6a463cadc8d8b65fc8ff6115ac39709c.jpg

a36c37f30ec4a600f04327f13ed12d3821f.jpg

9fbe10cb1715a0550c2afb100819c61c1fc.jpg

父子组件通信

(2)数量统计,tab切换面板,clear清除所选item

baa66622ba5b2de64072777dd0af03e2db6.jpg

7f9699e0af31a165b59bb7f01e60221513e.jpg

3f368123d64ef01493863836cb58a308cab.jpg

22186c35fac9a9f3d7d193d80f988271e2d.jpg

e12e50115182f06de0906516889adcacf2f.jpg

b1e9e44daf13529dade2df80df20b5d9ad2.jpg

至此代码:

tabs.vue

<template>
  <div class="helper">
    <span class="left">{{unFinishedTodoLength}} items left</span>
    <span class="tabs">
      <span
        v-for="state in states"
        :key="state"
        :class="[state, filter === state ? 'actived' : '']"
        @click="toggleFilter(state)"
      >
        {{state}}
      </span>
    </span>
    <span class="clear" @click="clearAllCompleted">
      Clear Completed
    </span>
  </div>
</template>

<script>
export default {
  props: {
    filter: {
      type: String,
      required: true
    },
    todos: {
      type: Array,
      required: true
    }
  },
  data(){
    return{
      states:['all', 'active','completed']
    }
  },
  methods: {
    clearAllCompleted (){
      this.$emit('clearAllcompleted')
    },
    toggleFilter(state){
      this.$emit('toggle', state)
    }
  },
  computed: {
    unFinishedTodoLength(){
      return this.todos.filter(todo => !todo.completed).length
    }
  }
}
</script>
<style lang="stylus" scoped>
.helper{
  text-align center
  .left{width:18%;display inline-block}
  .tabs{
    width 50%
    display inline-block
    margin 10px auto
    span{
      min-width 33%
      display inline-block 
      }
    span:hover{
      cursor pointer
      color orange
    }
    span.actived{
      color red
      }
    }
  .clear{ 
    width 30%
    display inline-block 
    color:grey
    border none
    outline none
    }
  .clear:hover{
    color black
    cursor pointer
    }
  input[type='button']{
    border-width 0
  }
}
</style>

todo.vue

<template>
  <section class="real-app">
    <input 
      type="text"
      class="add-input"
      autofocus='autofocus'
      placeholder="接下来要做什么"
      @keyup.enter="addTodo"
    >
    <item 
      :todo='todo'
      v-for="todo in filterdTodos"
      :key="todo.id"
      @del="deleteTodo"
    />
    <!-- @keyup 也就等于 v-on:keyup -->
    <tabs 
      :filter = 'filter' 
      :todos="todos"
      @toggle='toggleFilter'
      @clearAllcompleted="clearAllcompleted"
    
    />
  </section>
</template>
<script>
import Item from './item.vue'
import Tabs from './tabs.vue'
let id = 0
export default {
  data() {
    return{
      todos:[],
      filter:'all'
    }
  },
  methods: {
    addTodo(e){
      this.todos.unshift({
        id: id++,
        content: e.target.value.trim(),
        completed: false
      })
      e.target.value =''
    },
    deleteTodo(id){
      this.todos.splice(this.todos.findIndex(todo => todo.id === id), 1)
    },
    toggleFilter(state){
      this.filter = state
    },
    clearAllcompleted(){
      this.todos = this.todos.filter(todo => !todo.completed)
    }
  },
  computed: {
    filterdTodos(){
      if (this.filter === 'all'){
        return this.todos
      }
      // 判断
      const completed = this.filter === 'completed'
      return this.todos.filter(todo => completed === todo.completed)
    }
  },
  components: {
    Item,Tabs
  }
}
</script>
<style lang=stylus scoped>
.real-app{
  width 70%
  min-width 500px
  padding 10px
  background #ffffff
  color #555555
  margin 20px auto
  box-shadow 0 0 10px 5px rgba(0,0,0,0.5)
  .add-input{
    width 84%
    font-size 24px
    border none
    margin 0 6%
    padding 20px 2%
    outline none
    border-bottom 1px solid #fff
  }
  .add-input:hover{
    color #333
    border-bottom 1px solid #ccc
    cursor pointer
  }
}
</style>

item.vue 

<template>
  <div :class="['todo-item',todo.completed ? 'completed' : '']">
    <input 
      type="checkbox"
      class="toggle"
      v-model="todo.completed"
    >
    <label>{{todo.content}}</label>
    <button class="destory" @click="deleteTodo"></button>
  </div>
</template>
<script>
export default {
  props:{
    todo:{
      type:Object,
      required:true
    }
  },
  methods:{
    deleteTodo(){
      this.$emit('del', this.todo.id)
    }
  }
}
</script>

<style lang=stylus scoped>
.todo-item{
  vertical-align text-top
  border none
  padding 15px 2%
  width 88%
  margin 10px 4%
  border-bottom 1px solid #eee
  font-size 28px
  input[type="checkbox"],input[type="checkbox"]:checked{
    vertical-align text-top
    width 30px
    height 30px
  }
  .destory{
    width 30px
    height 30px
    float  right
  }
}
</style>

 

三、webpack配置优化

1. 配置css单独分离打包

npm i extract-text-webpack-plugin

 3204f4e3ddf4c512f8b70ffcce598b46bda.jpg

添加引入,isDev判断为true,false,同时剪切module-rules-styl的编译

7e257c2823f2675b7e7071d370b97deca68.jpg

粘贴到dev时候的设置里

3cd1202986efe326c3036d4fe31d6e2dfa9.jpg

增加else里的判断,style-loader可以用fallback,打包后的速度更快

const path = require('path')

const HTMLPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const ExtractPlugin = require('extract-text-webpack-plugin')
const isDev = process.env.NODE_ENV === 'development'

const config = {
  target: 'web',
  entry:path.join(__dirname,'src/index.js'),
  output: {
    filename: 'bundle[hash:8].js',
    path: path.join(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.jsx/,
        loader: 'babel-loader'
      },
      {
        test: /\.(gif|jpg|jepg|png|svg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 1024,
              name: '[name]-aaa.[ext]'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: isDev ? '"development"' : '"production"'
      }
    }),
    new HTMLPlugin()
  ]
}

if (isDev) {
  config.module.rules.push({
      test: /\.styl/,
      use: [
        'style-loader',
        'css-loader',
        {
          loader: 'postcss-loader',
          options: {
            sourceMap: true,
          }
        },
        'stylus-loader'
      ]
  })
  config.devtool = '#cheap-module-eval-source-map' // 浏览器打开后,通过映射以编译后我们能看懂方式调整,source-map最完整映射关系,但是编译效率比较低,文件比较大,eval可能看起来会比较乱,出现行对应不齐的问题。而推荐的这个效率比较高
  config.devServer = {
    port: 8000,
    host: '0.0.0.0',
    overlay: {
      errors: true,
    },
    hot: true // 改了一个组件的代码,只重新渲染这个组件,不贵整个页面渲染
    // historyFallback: {

    // }// 入口地址映射,(略)
    // open: true //启动后自动打开页面
  },
  config.plugins.push(
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin() // 不需要信息展示的问题
  )
} else{
  config.output.filename = '[name][chunkhash:8].js'
  config.module.rules.push(
    {
      test: /\.styl/,
      use: ExtractPlugin.extract({
        fallback: 'style-loader',
        use: [
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: true
            }
          },
          'stylus-loader'
        ]
      })
    }  
  ),
  config.plugins.push(
    new ExtractPlugin('styles.[contentHash:8].css')
  )
}

module.exports = config
npm run build

e262f238cdbf8962fcdfcbb601271a21310.jpg

打包生成文件名

附带:package.json

{
  "name": "vue-ssr-tech",
  "version": "1.0.0",
  "description": "",
  "main": "webpack.config.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
    "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "autoprefixer": "^7.2.3",
    "babel-core": "^6.26.3",
    "babel-helper-vue-jsx-merge-props": "^2.0.0",
    "babel-loader": "^7.1.2",
    "babel-plugin-syntax-jsx": "^6.18.0",
    "babel-plugin-transform-vue-jsx": "^3.7.0",
    "babel-preset-env": "^1.7.0",
    "cross-env": "^5.1.3",
    "css-loader": "^0.28.7",
    "extract-text-webpack-plugin": "^3.0.2",
    "file-loader": "^1.1.11",
    "html-webpack-plugin": "^3.2.0",
    "postcss-loader": "^3.0.0",
    "style-loader": "^0.22.1",
    "stylus": "^0.54.5",
    "stylus-loader": "^3.0.2",
    "url-loader": "^1.0.1",
    "vue": "^2.5.17",
    "vue-loader": "^13.7.2",
    "vue-template-compiler": "^2.5.17",
    "webpack": "^3.10.0",
    "webpack-dev-server": "^2.9.7"
  },
  "devDependencies": {}
}

如有版本报错,可根据上面替换安装

2.区分打包类库代码及hash优化

让浏览器加载更快

8f2798030855f158999d10c2187affb95a6.jpg

3c02517f405050d73d14daeb8f99bfff4ad.jpg

npm run build

a3757df34394cb653b12bb54acf0319d414.jpg

hash和chunkhash区别:

eb2a1647c75c28d9b44878a76577be2678f.jpg

chunkhash是每个模块一个hash,hash会有区别,而hash是整个应用一个hash

36fa02e7b940cb88aff2c4d9b78591b683e.jpg

webpack.config.js

const path = require('path')

const HTMLPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const ExtractPlugin = require('extract-text-webpack-plugin')
const isDev = process.env.NODE_ENV === 'development'

const config = {
  target: 'web',
  entry:path.join(__dirname,'src/index.js'),
  output: {
    filename: 'bundle[hash:8].js',
    path: path.join(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.jsx/,
        loader: 'babel-loader'
      },
      {
        test: /\.(gif|jpg|jepg|png|svg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 1024,
              name: '[name]-aaa.[ext]'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: isDev ? '"development"' : '"production"'
      }
    }),
    new HTMLPlugin()
  ]
}

if (isDev) {
  config.module.rules.push({
      test: /\.styl/,
      use: [
        'style-loader',
        'css-loader',
        {
          loader: 'postcss-loader',
          options: {
            sourceMap: true,
          }
        },
        'stylus-loader'
      ]
  })
  config.devtool = '#cheap-module-eval-source-map' // 浏览器打开后,通过映射以编译后我们能看懂方式调整,source-map最完整映射关系,但是编译效率比较低,文件比较大,eval可能看起来会比较乱,出现行对应不齐的问题。而推荐的这个效率比较高
  config.devServer = {
    port: 8000,
    host: '0.0.0.0',
    overlay: {
      errors: true,
    },
    hot: true // 改了一个组件的代码,只重新渲染这个组件,不贵整个页面渲染
    // historyFallback: {

    // }// 入口地址映射,(略)
    // open: true //启动后自动打开页面
  },
  config.plugins.push(
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin() // 不需要信息展示的问题
  )
} else{
  config.entry = {
    app: path.join(__dirname,'src/index.js'),
    vendor: ['vue']
  }
  // config.output.filename = '[name].[hash:8].js'
  config.output.filename = '[name].[chunkhash:8].js'
  config.module.rules.push(
    {
      test: /\.styl/,
      use: ExtractPlugin.extract({
        fallback: 'style-loader',
        use: [
          'css-loader',
          {
            loader: 'postcss-loader',
            options: {
              sourceMap: true
            }
          },
          'stylus-loader'
        ]
      })
    }  
  ),
  config.plugins.push(
    new ExtractPlugin('styles.[contentHash:8].css'),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'verdor'
    }),
    // 在有新的模块加入的时候,webpack是会给新模块加入id的,插入顺序不同,倒是id会变化,使用浏览器的缓存就是去效果,这种方式可以规避。verdor要放在runtime前面
    new webpack.optimize.CommonsChunkPlugin({
      name: 'runtime'
    })
  )
}

module.exports = config

四、总结

搭建项目-webpack构建(eg:vue-loader,jsx->babel,静态资源,缓存)

webpack中文网:https://www.webpackjs.com/

webapck官网(要翻墙):http://webpack.github.io/

配置很多

vue开发todo应用,.vue文件,数据传递,拆分组建,双向绑定,虚拟DOM,jsx文件-复杂场景(vue2)

fb62928e42a2364208e3b81e163582ea1a7.jpg

 

 

 

错误解答

1.No parser and no filepath given

npm install vue-loader@^13.7.2

2.You may need an appropriate loader to handle this file type

解决:可能有些包的版本不合适,需要更改

转载于:https://my.oschina.net/u/3018050/blog/1924538

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值