从零开始搭建Vue工程

2022-09-08 18:09:42 浏览数 (3)

项目骨架

代码语言:javascript复制
 object
  --dist
    --src
      ----assets
      ------images
      ------styles
      ----index.js
      ----app.vue
    --webpack.config.js

dist目录存放编译后的资源 src存放源码文件 运行命令 npm init -y

one

首先安装基础包 npm i webpack webpack-cli npm i vue vue-loader vue-template-compiler css-loader style-loader

在/src/app.vue键入如下测试代码

代码语言:javascript复制
<template>
  <h1>
      {{title}}
  </h1>
</template>

<script>
export default {
    data(){
        return {
            title:'Hello Vue!'
        }
    }
}
</script>

<style>

</style>

在/src/index.js键入如下代码

代码语言:javascript复制
import Vue from 'vue'
import app from './app'
const root = document.createElement('div')
document.body.appendChild(root)
new Vue({
    render:(h)=>h(app)
}).$mount(root)

上面代码的创建了一个vue实例,并将其挂载到html节点

由于使用了.vue文件我们要配置webpack,并且设置resolve修改vue的默认引入

webpack 默认引入vue版本是一个运行时版本,开发阶段我们将其修改为完整的版本

在/webpack.config.js键入如下

代码语言:javascript复制
const path = require('path')

module.exports = {
    mode:"development",
    entry:{
        path:path.join(__dirname,"./src/index.js"),
    },
    output:{
        path:path.join(__dirname,"dist"),
        filename:"bundle.js"
    },
    module:{
        rules:[
            {test:/.vue$/,loader:"vue-loader"}
        ]
    },
    resolve:{
       extensions:[".vue",".js",".jsx",".json"],
        alias:{
            "vue":"vue/dist/vue.esm.js"
        }

    }
}

接下来在package.json设置编译资源的命令

代码语言:javascript复制
...
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "dev": " webpack --config webpack.config.js"
  },
...

运行命令 npm run dev 报错如下

代码语言:javascript复制
ERROR in ./src/app.vue
Module Error (from ./node_modules/vue-loader/lib/index.js):
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.

我们要配置一个VueLoaderPlugin的插件才可以

代码语言:javascript复制
//webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')
...
 plugins:[
        new VueLoaderPlugin()
    ]
}

再次运行命令 npm run dev即可

这个时候项目dist目录会生成bundle.js文件代码资源编译成功,博主这里暂不测试

two

上面我们已经可以将vue文件编译出来,这个时候可以考虑一些静态资源文件,比如css,图片资源等。

由于之前我们已经引入了css-loader ,style-loader先以css文件为例, css 补充webpack.config.js

代码语言:javascript复制
 rules:[
            {test:/.vue$/,loader:'vue-loader'},
            {test:/.css$/,use:['style-loader','css-loader']}
        ]

在/src/index.js中引入/src/assets/styles/index.js文件

代码语言:javascript复制
...
import './assets/styles/index.css'
...

运行命令 npm run dev 可以在bundle.js看到如下代码,这就是index.css的内容

代码语言:javascript复制
body{\r\n    background-color: red;\r\n}", ""])

图片资源

接下来我们可以试着打包项目中用到的图片 在 /src/assets/styles/index.js键入如下代码

代码语言:javascript复制
body{
    background-image: url('../images/bg.jpeg');
}

下载图片处理相关的包

代码语言:javascript复制
npm i url-loader file-loader

补充webpack.config.js

代码语言:javascript复制
 rules:[
            {test:/.vue$/,loader:'vue-loader'},
            {test:/.css$/,use:['style-loader','css-loader']},
            {
                test:/.(jpg|jpeg|png|gif|svg)$/,
                use:[
                    {
                        loader:'url-loader',
                        options:{
                             //小于1M的转换为base64
                             limit:1024,
                             name:'[name].[ext]'
                        }
                    }
                ]
            }
        ]

这里的loader使用了另一种配置方法,我们给url-loader设置了一些选项,具体参照 运行命令 npm run dev 在/dist/生成了bg.jpeg文件

此时可以使用普通的html文件引入bundle.js看看是否改变了body的背景。

css预处理

在项目中我们一般会用到css预处理器,那么这些与处理器如何通过webpack编译成普通的css文件 这里有stylus为例 安装stylus相关的包 npm i stylus stylus-loader 补充webpack.config.js

代码语言:javascript复制
...
{test:/.styl/,use:['style-loader','css-loader','stylus-loader']},
...

运行 npm run dev 可以在bundle.js中看到stylus语法最终被编译成了css

代码语言:javascript复制
h1[data-v-5ef48958] {\n  color: #333;\n}\nh1 span[data-v-5ef48958] {\n  font-size: 28px;\n}

three

区分环境

到目前为止我们的项目还没有跑起来过,这里我们可以使用devServer让我们的项目运行起来 由于devServer是运行在开发环境,所以我们区分环境的方式去配置webpack.config.js 引入 cross-env 用于区分当前环境 npm i cross-env 修改package.json

代码语言:javascript复制
"scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "build":"cross-env NODE_ENV=production webpack",
    "dev":"cross-env NODE_ENV=development webpack"
  },

接下来我们就可以使用process.env获取到当前环境 在webpack.config.js

代码语言:javascript复制
const path = require('path')
const isDev = process.env.NODE_ENV === 'development'
...

当然只区分环境是不够的,我们一般有三套配置,分别为基础配置、开发配置、生产配置然后根据环境变量运行不同的配置文件

引入模块合并配置文件 npm i webpack-merge -D 1.将webpack.config.js更名为webpack.base.js 2.新建webpack.dev.js用于设置开发环境配置 3.新建webpack.pro.js用于设置线上环境配置

webpack.base.js的内容

代码语言:javascript复制
const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const webpack = require('webpack')
const HTMLPlugin = require('html-webpack-plugin')
const isDev = process.env.NODE_ENV === 'development'

module.exports = {
    
    entry:{
        path:path.join(__dirname,"./src/index.js"),
    },
    output:{
        path:path.join(__dirname,"dist"),
        filename:"bundle.js",
        publicPath:'./'
    },
    module:{
        rules:[
            {test:/.vue$/,loader:'vue-loader'},
            {test:/.css$/,use:['style-loader','css-loader']},
            {test:/.styl/,use:['style-loader','css-loader','stylus-loader']},
            {
                test:/.(jpg|jpeg|png|gif|svg)$/,
                use:[
                    {
                        loader:'url-loader',
                        options:{
                             //小于1M的转换为base64
                             limit:1024,
                             name:'[name].[ext]'
                        }
                    }
                ]
            }
        ]
    },
    resolve:{
        extensions:[".vue",".js",".jsx",".json"]

    },
    plugins:[
        new VueLoaderPlugin(),
        new webpack.DefinePlugin({
            'process.env':{
                NODE_ENV:isDev ? '"development"' : '"production"'
            }
        }),
        new VueLoaderPlugin(),
        new HTMLPlugin()
    ]
}

在webpack.base.js中我们进行了如下操作

1.我们移除了moderesolve.alias配置项,因为这个两个配置项要区分环境去配置

2.设置了webpackDefinePlugin使当前环境能够在普通的js中得到应用 比如index.js使用console.log(process.env.NODE_ENV)

3.引入了HTMLPlugin,这个插件用于帮我们生成html 4.配置了output.publicPath设置资源的根路径

在webpack.dev.js键入如下代码

代码语言:javascript复制
const merge = require('webpack-merge');
const base = require('./webpack.base.js');
const webpack = require('webpack')
module.exports =  merge(base,{
    mode:'development',
    devServer:{
        port:520,
        host:'127.0.0.1',
        overlay:{
            errors:true //有错误时显示在网页上
        },
        hot:true//配置热更新
    },
    resolve:{
        alias:{
            "vue":"vue/dist/vue.esm.js"
        }
    },
    plugins:[
        //热更新
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin(),
    ]
})

在webpack.pro.js键入如下代码

代码语言:javascript复制
let  merge  = require('webpack-merge');
let base = require('./webpack.base.js');
module.exports =  merge(base,{
    mode:'production',
    resolve:{
        alias:{
            "vue":"vue/dist/vue.runtime.esm.js"
        }
    }
})

安装 npm i webpack-dev-server 高版本的cli 安装 @webpack/cli-serve npm i html-webpack-plugin

修改package.json

代码语言:javascript复制
 "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "build": "cross-env NODE_ENV=production webpack  --config webpack.pro.js",
    "dev": "cross-env NODE_ENV=development webpack serve --config webpack.dev.js"
  },

运行开发环境的命令 npm run dev 访问 localhost:520 可以看到项目运行成功

接下来我们在测试生产环境的命令 npm run build 生成如下文件

jsx

在vue中我们也可以使用jsx语法,用jsx写出来的组件比较灵活

代码语言:javascript复制
npm i babel-plugin-transform-vue-jsx  babel-plugin-syntax-jsx

安装预设 npm i @babel/core babel-loader @vue/babel-preset-app 配置.babelrc

代码语言:javascript复制
{
    "presets": [
        "@vue/babel-preset-app"
    ]
}

补充webpack.base.js

代码语言:javascript复制
{test:/.jsx/,loader:'babel-loader'},

写一个jsx测试组件

代码语言:javascript复制
//footer.jsx
export default {
    data(){

    },
    render(){
        return (
            <footer>copy right tzh</footer>
        )
    }
}

css自动加浏览器前缀

npm i postcss-loader autoprefixer 项目新建配置文件 postcss.config.js并键入如下代码

代码语言:javascript复制
const autoprefixer = require('autoprefixer')
module.exports = {
  plugins:[
    autoprefixer()
  ]
}

接下来修改相应配置,在css-loader处理前先交给postcss-loader处理

代码语言:javascript复制
{
    test:/.styl$/,
    use:[
        'style-loader',
        'css-loader',
        {
            loader:'postcss-loader',
            options:{
                sourceMap:true
            }
        },//添加postcss处理
        /**因为stylus-loader会自动生成sourceMap所以postcss-loader直接使用前面生成的即可 */
        'stylus-loader'
    ]
}

到此我们可以说一个基本的Vue工程搭建完毕,当然其他的一些配置根据业务扩展即可比如es5 语法 由于每个项目的业务需求都不一样,这里只搭建基础工程 但是我们还可以对项目进行一些优化

优化

单独分离css

上面的配置是将css写到bundle.js里面的,一个线上的项目肯定不能这样做,我们要将其单独抽离处理充分利用浏览器的缓存机制! npm i mini-css-extract-plugin 文档

我们将webpack.base.js里面配置的styl(css同理)删除,区分环境处理

代码语言:javascript复制
 rules:[
            {test:/.vue$/,loader:'vue-loader'},
            /*{test:/.css$/,use:['style-loader','css-loader']},*/
           /* {test:/.styl/,use:['style-loader','css-loader','stylus-loader']},*/
            {test:/.jsx/,loader:'babel-loader'},

webpack.dev.js

代码语言:javascript复制
 devServer:{
        port:520,
        host:'127.0.0.1',
        overlay:{
            errors:true //有错误时显示在网页上
        },
        hot:true//配置热更新
    },
    module:{
        rules:[
            {
                test:/.styl$/,
                use:[
                    'style-loader',
                    'css-loader',
                    {
                        loader:'postcss-loader',
                        options:{
                            sourceMap:true
                        }
                    },//添加postcss处理
                    /**因为stylus-loader会自动生成sourceMap所以postcss-loader直接使用前面生成的即可 */
                    'stylus-loader'
                ]
            }
        ]
    },
...

在webpack.pro.js

代码语言:javascript复制
let merge = require('webpack-merge');
let base = require('./webpack.base.js');
let MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports =  merge(base,{
    mode:'production',
    resolve:{
        alias:{
            "vue":"vue/dist/vue.runtime.esm.js"
        }
    },
    module:{
        rules:[
            {
                test:/.styl$/,
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    {
                        loader:'postcss-loader',
                        options:{
                            sourceMap:true
                        }
                    },//添加postcss处理
                    'stylus-loader'
                ]
            }
        ]
    },
    plugins:[
        new MiniCssExtractPlugin({
            filename:'main.css'//生成的样式文件名称
        })
    ]
})

npm run build

cssb被单独打包

单独打包类库文件

因为类库代码的稳定性较高,不需要经常迭代 我们需要浏览器尽可能长时间去缓存我们的静态文件 如果将类库文件和js文件打包到一起,那么类库文件将随着我们js 文件更新而更新,这样就不能最大限度的利用浏览器缓存

这个时候我们就不能以将所有文件都取名为bundle.js

在webpack.pro.js添加

代码语言:javascript复制
...
 output:{
        filename:"[name].[chunkhash:8].js"
    },
...

完整的webpack.pro.js

代码语言:javascript复制
let merge = require('webpack-merge');
let base = require('./webpack.base.js');
let MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports =  merge(base,{
    mode:'production',
    resolve:{
        alias:{
            "vue":"vue/dist/vue.esm.js"
        }
    },
    output:{
        filename:"[name].[chunkhash:8].js"
    },
    module:{
        rules:[
            {
                test:/.styl$/,
                use:[
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    {
                        loader:'postcss-loader',
                        options:{
                            sourceMap:true
                        }
                    },//添加postcss处理
                    'stylus-loader'
                ]
            }
        ]
    },
    plugins:[
        new MiniCssExtractPlugin({
            filename:'main.css'//生成的样式文件名称
        })
    ],
    optimization:{
        splitChunks:{
            //分隔代码块
            cacheGroups:{
                //缓存组
                vendor:{
                    //引用多次第三方模块
                    priority:1,//先抽离第三方模块
                    test:/node_modules/,
                    chunks:'initial',//入口处开始
                    minSize:0,//>0字节
                    minChunks:1,//用过1次以上
                }
            }
        }
    }    
})

hash与chunkhash的区别

chunk:可以理解为在entry里面声明的不同节点 hash:所有打包的js模块都是同一个hash

所以类库打包时使用chunkhash,如果使用hash那么普通js文件改变后 类库文件也随着改变,这样就没有充分利用浏览器缓存

0 人点赞