(todo应用)构建初步webpack+vue的环境

学习地址:慕课网:Vue+webpack

github地址:todo应用源码

教程中老师所用的webpack是3.0,直接使用最新版的构建时有些许不同,特此记录,以免遗忘。

webpack:使用其作为构建工具,将静态资源(js,css,图片,字体...)打包,使之能够在html中正常运行  =>能够减少http请求

1. 目录结构如下图,首先创建src文件夹存放静态资源,dist是打包之后指定生成的文件,node_modeules是npm 命令安装的所需插件的文件夹


2. 初始化环境

npm init -y     //-y(代表yes),则跳过提问阶段,直接生成一个新的 package.json 文件。
    安装webpack ,vue,vue-loader
 npm i webpack vue vue-loader
`会出现警告,提示需要安装两个依赖css-loader,vue-template-compiler`

3. 创建文件assets/app.vue

<template>
    <div id="text">{{text}}</div>
</template>

<script>
    export default {
        data() {
            return {
                text:"内容"
            }
        }
    };
</script>

<style>
#text {
    color: #fff;
}
</style>

设置入口文件,创建assets/index.js

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

const root = document.createElement('div')
document.body.appendChild(root)
// h参数是vue中的createApp参数
new Vue({ render:(h) => h(App) // 声明了组件渲染出来的是app的内容}).$mount(root) //然后挂载到节点上

设置webpack配置,根目录下创建文件webpack.config.js

const path = require('path') //path是webpack中的基本包,处理路径
const config = {
    //入口文件
    entry: path.join(__dirname, 'src/index.js'),   //__dirname表示当前文件所在的目录地址,利用join()拼接成绝对路径
    // 输出文件
    output: {
        filename: 'bundle.js',//输出文件名
        path: path.join(__dirname, 'dist')
    }
}
module.exports = config

 并且在package.json中添加脚本build信息

 "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --config webpack.config.js --mode production",  //--mode production能够指定运行的时候为生产模式
}

然后npm run build 

warn:    提示需要安装webpack-cli

npm install -D webpack-cli

warn:    提示You may need an appropriate loader to handle this file type.

先安装用于解析样式的包:

npm i style-loader

需要指定不同的文件类型,webpack.config.js中添加

(注意两点:1. 需要添加VueLoaderPlugin 插件  2.plugins插件的位置是在module之外):

const path = require('path') //path是webpack中的基本包,处理路径
const VueLoaderPlugin = require('vue-loader/lib/plugin')   // 1. 添加插件

const config = {
    //入口文件
    entry: path.join(__dirname, 'src/index.js'),   //__dirname表示当前文件所在的目录地址,利用join()拼接成绝对路径
    // 输出文件
    output: {
        filename: 'bundle.js',//输出文件名
        path: path.join(__dirname, 'dist')
    },
    module: {
        rules: [
        {
            // 以vue-load 处理以vue结尾的文件,确保正确输出js代码
            test: /\.vue$/,
            loader: 'vue-loader'
        },
        {
            test:/\.css$/,
            // style-loader是将外部css文件注入html文件中,最后将html文件中的css 用css-loader进行解析
            use: [
                'style-loader',
                'css-loader'
            ]
        }
        ]
    },
    plugins: [            //插件的位置
        new VueLoaderPlugin()
    ]
}

接着 npm run build 就能够运行了。在dist文件夹下输出文件名为bundle.js的文件。

4.   加载各种静态资源的方法

在styles文件下创建两个文件夹:

style.css:

body {
    color: #ccc;
    background-image: url('../images/1.jpg');
}

test.style.styl:

body 
    font-size 12px

在styles文件下创建images文件,并且放入图片,之后在index.js中引入上述文件:

import './assets/styles/style.css'
import './assets/styles/test-style.styl'
import './assets/images/1.jpg'

在webpack.config.js中设置文件的处理方式:

        {
            test: /\.styl$/,
            use: [
                'style-loader',
                'css-loader'
                'stylus-loader'
            ]
        },
        {
            test: /\.(gif|jpg|jpeg|png|svg)$/,
            use:[
            {
                loader: 'url-loader',
            //将图片转化成base64的代码,直接写在js内容里而不用生成新的文件,减少http请求
            //还可以指定输出的文件名字,
                options: {
                    limit:1024,
                    name:'[name]-aaa.[ext]'
                }
            }
            ]
        }

然后运行:npm i url-loader file-loader stylus-loader stylus,下载包。

再npm run dev ,可以看到输出的不同文件。

5. 配置webpack.devServer ,创建高效开发模式

安装: npm i cross-dev

配置: package.js中:

    "build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
    "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"

下载插件,使html自动包含js:

npm i html-webpack-plugin webpack-dev-server cross-env

在webpack.config.js中配置:

const path = require('path') 
const HtMLPlugin = require('html-webpack-plugin') // 新建插件
const VueLoaderPlugin = require('vue-loader/lib/plugin')
// // 启动脚本时的变量存在于process.env变量中
const isDev = process.env.NODE_ENV === 'development'
const webpack = require('webpack')   //

const config = {
    // webpack的编译目标是web平台
    target: 'web',
    //入口文件
    entry: path.join(__dirname, 'src/index.js'),   //__dirname表示当前文件所在的目录地址,利用join()拼接成绝对路径
    // 输出文件
    output: {
        filename: 'bundle.js',//输出文件名
        path: path.join(__dirname, 'dist')
    },
    module: {
        rules: [
        {
            // 以vue-load 处理以vue结尾的文件,确保正确输出js代码
            test: /\.vue$/,
            loader: 'vue-loader'
        },
        {
            test:/\.css$/,
            // style-loader是将外部css文件注入html文件中,最后将html文件中的css 用css-loader进行解析
            use: [
                'style-loader',
                'css-loader'
            ]
        },
        {
            test: /\.styl$/,
            use: [
                'style-loader',
                'css-loader',
                'stylus-loader'
            ]
        },
        {
            test: /\.(gif|jpg|jpeg|png|svg)$/,
            use:[
            {
                loader: 'url-loader',
            //将图片转化成base64的代码,直接写在js内容里而不用生成新的文件,减少http请求
            //还可以指定输出的文件名字,
                options: {
                    limit:1024,
                    name:'[name]-aaa.[ext]'
                }
            }
            ]
        }
        ]
    },
    plugins: [
    //能够在js代码中引用到,并且vue也能够根据此进行分类打包
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: isDev ? '"development"' : '"production"'
            }
        }),
        new HtMLPlugin(),  //插件添加使用
        new VueLoaderPlugin()
    ]
}

// // 配置是根据不同的环境判断,通过设置一个环境变量来判断
if (isDev) {
    config.devtool = '#cheap-module-eval-source-map'  //帮助在页面上调试代码, 优化显示  
    config.devServer = {
        port: 8088,
        //host 可以通过localhost进行访问,同时也可以通过本机的内网id进行访问,就能够在别的网页或者手机上访问
        host:'0.0.0.0',
        //overlay 编译过程有任何错误都直接显示到网页上
        overlay: {
            errors: true
        },
        // 当修改组件代码时,只重新渲染当前组件,不会让整个页面重新加载;hot启动后要添加以下两个插件
        hot: true

        // 能够在运行后直接打开浏览器
        // open: true
    }
    // 启动webpack.hot功能的插件
    config.plugins.push(
        new webpack.HotModuleReplacementPlugin(), //启动hot功能
        new webpack.NoEmitOnErrorsPlugin()    //减少不需要信息的提示  
        )
}
module.exports = config

之后运行,npm run dev 就能够在localhost:8080端口查看

6. 配置vue的 jsx以及postcss

安装插件:

 npm i postcss-loader autoprefixer babel-loader babel-core
 npm i babel-preset-env babel-plugin-transform-vue-jsx

提示缺少依赖:

 npm i babel-helper-vue-jsx-merge-props

根目录下创建文件夹,postcss.config.js,.babelrc

postcss.config.js:

//自动处理css属性 ,自动补全css前缀
const autoprefixer = require('autoprefixer')

module.exports = {
    plugins: [
        autoprefixer()
    ]
}
.babelrc:
{
    "presets": [
        "env"
    ],
    "plugins": [
        "transform-vue-jsx"    
    ]
}

并且在webpack.config.js中配置相关rules:

        {
            test: /\.jsx$/,
            loader: 'babel-loader'
        },
        {
            test: /\.styl$/,
            use: [
                'style-loader',
                'css-loader',
                {
                    loader: 'postcss-loader',
                    options: {
                        sourceMap: true, //指定这个值,后面stylus编译的时候就不用重新定值,编译效率变快
                    }
                },
                'stylus-loader'
            ]
        }
运行 npm run dev 即可。

7. 创建todo应用

业务逻辑: 所有数据都在顶层组件todo.vue中。

todo.vue中设置的addTodo() 方法,input组件设置按下enter键后调用方法: @keyup.enter="addTodo"

添加一列:递增的id,内容以及未完成的初始态。

            addTodo(e) {
                if (e.target.value.trim()) {
                    this.todos.unshift({
                        id: id++,    
                        content: e.target.value.trim(),
                        completed: false
                    });
                    e.target.value = '';        //每次结束需要内容清空
                } else {
                    alert('输入不能为空 !');
                }
            },

删除一列: 接受子组件传递的参数,进行更改

deleteTodo(id) {
      this.todos.splice(this.todos.findIndex(todo => todo.id === id), 1)
    },

利用计算属性获得未完成项:在tabs.vue子组件中,需要接收父组件的todos数据,unFinishedTodoLength() {

      return this.todos.filter(todo => !todo.completed).length;
    }

状态的切换:

子组件tabs.vue中通过遍历数组,点击事件并且将state状态传递给父组件:

           states: ['all', 'active', 'completed']

父组件todu.vue中接受事件,并且设置filter值为当前选中状态值:

            toggleFilter(state) {
                this.filter = state;  // filter为一个当前状态的字符串
            },

删除已完成项:(filter 不会改变原数组,它返回过滤符合规则后的新数组。)

              clearAllCompleted() {
                // 给todos赋一个新的值(即todo.completed为false的值)
                this.todos = this.todos.filter(todo => todo.completed === false)

            }

根据需求显示对应项目:(遍历 计算属性)

            filteredTodos() {
                if (this.filter === 'all') {
                    return this.todos;                //显示全部值
                }
                const completed = this.filter === 'completed';        //显示完成值

                // 将todos数组中,completed为true的值过滤出来,并返回一个新数组
                return this.todos.filter(todo => completed === todo.completed);

            }

8 . webpack 打包优化

安装插件,将非js的文件单独打包成静态文件

 npm i extract-text-webpack-plugin

会出现错误提示,

npm WARN [email protected] requires a peer of webpack@^3.1.0 but none is installed. You must install peer dependencies yourself.

如果照上面所说去安装webpack 3.0版本的,会让之前webpack-cli等都得降低版本,所以在package.json中设置:

    "extract-text-webpack-plugin": "^4.0.0-beta.0",

然后在安装,OK!

(css打包): 使用不同的vendor或则不同的文件进行打包,需要使用chunkhash,能够保证生成的hash值不同

const config = {
    // 修改输出文件
    output: {
        filename: 'bundle.[hash:8].js',//输出文件名,开发环境不能使用chunkhash,正式环境中需要进行一个修改
        path: path.join(__dirname, 'dist')
    },
}

// // 配置是根据不同的环境判断,通过设置一个环境变量来判断
if (isDev) {
    //如果是开发环境
    config.module.rules.push({
            test: /\.styl/,
            use: [
                'style-loader',
                'css-loader',
                // {
                     'postcss-loader',
                //     options: {
                //         sourceMap: true, //指定这个值,后面stylus编译的时候就不用重新定值,编译效率变快
                //     }
                // },
                'stylus-loader'
            ]
    });
    config.devtool = '#cheap-module-eval-source-map'
    config.devServer = {
        port: 8088,
        //host 可以通过localhost进行访问,同时也可以通过本机的内网id进行访问,就能够在别的网页或者手机上访问
        host:'0.0.0.0',
        //overlay 编译过程有任何错误都直接显示到网页上
        overlay: {
            errors: true
        },
        // 当修改组件代码时,只重新渲染当前组件,不会让整个页面重新加载
        hot: true

        // 能够在运行后直接打开浏览器
        // open: true
    }
    // 启动webpack.hot功能的插件
    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',
                    'postcss-loader',
                    'stylus-loader'
                ]
            })
    });
    config.plugins.push(
        // 指定输出的静态文件的名字
        new ExtractPlugin('styles.[chunkhash:8].css')
        )
}

(打包类库代码):利用浏览器的缓存减少服务器的流量以及使用户加载速度更快

按照教程添加:

    config.entry = {
        app: path.join(__dirname, 'src/index.js'),   //__dirname表示当前文件所在的目录地址,利用join()拼接成绝对路径
        vendor: ['vue']
    }
    config.plugins.push(
        // 类库文件单独打包
        new webpack.optimize.CommonsChunkPlugin({
            name: "vendor"
        })  //webpack单独打包
        new webpack.optimize.CommonsChunkPlugin({
            name: 'runtime'
        })
        )

发现 CommonsChunkPlugin() 已经在webpack4.0中移除,需要使用splitChunks()

        config.optimization = {
        splitChunks: {
            cacheGroups: {                  // 这里开始设置缓存的 chunks
                commons: {
                    chunks: 'initial',      // 必须三选一: "initial" | "all" | "async"(默认就是异步)
                    minSize: 0,             // 最小尺寸,默认0,
                    minChunks: 2,           // 最小 chunk ,默认1
                    maxInitialRequests: 5   // 最大初始化请求书,默认1
                },
                vendor: {
                    test: /node_modules/,   // 正则规则验证,如果符合就提取 chunk
                    chunks: 'initial',      // 必须三选一: "initial" | "all" | "async"(默认就是异步)
                    name: 'vendor',         // 要缓存的 分隔出来的 chunk 名称
                    priority: 10,           // 缓存组优先级
                    enforce: true
                }
            }
        },
        runtimeChunk: true
    } 

然后npm run build ,可以看到相应的哈希名字的文件生成。

猜你喜欢

转载自blog.csdn.net/weixin_41892205/article/details/80949601
今日推荐