webpack从零开始搭建Vue项目

webpack从零开始搭建Vue项目

包含:vue-router/vuex/scss支持/热加载等,从创建文件夹开始,内容稍微有点长,通过这个配置可以对webpack有一个基础的了解

源码下载地址,觉得有用点个star谢谢~

一、 项目初始化

在存放项目的地方打开命令行窗口,依次执行以下命令:

  1. mkdir vue-demo创建文件夹
  2. cd vue-demo进入文件夹
  3. npm init -y初始化项目

二、 webpack初始化

  1. 安装webpack,执行命令npm install webpack webpack-cli -D
  2. 修改package.json,添加启动命令
// vue-demo/package.json
{
    ...
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "dev": "webpack --mode development",
      "build": "webpack --mode production"
    },
    ...
}
  1. vue-demo下创建src文件夹,用于存放vue项目主要文件(vue-cli脚手架也是这么干的,咱也这么干,尽量接近vue-cli脚手架)
  2. vue-demo/src下创建main.js,作为项目的入口文件
  3. vue-demo下创建webpack.config.js文件,用于配置webpack
// vue-demo/webpack.config.js
const path = require('path');
module.exports = {
    entry: './src/main.js', // 入口文件
    output: { // 输出
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
    }
};
  1. 此时已经可以执行打包了,打包命令npm run build,dist为打包输出的文件

三、 创建HTML模板

html模板可以让我们加入一些自定义或第三方的工具

  1. vue-demo下创建index.html
// vue-demo/index.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
        <title>vue&&webpack</title>
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <style>
            body{
                background-color: red;
                color: #fff;
            }
        </style>
	</head>
	<body>
        <div id="app">
            <h1>Hello World</h1>
        </div>
	</body>
</html>
  1. 使用html-webpack-plugin创建模板,执行npm install html-webpack-plugin -D
  2. 修改webpack.config.js
// vue-demo/webpack.config.js
const path = require('path');
module.exports = {
    entry: './src/main.js', // 入口文件
    output: { // 输出
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './index.html',
            minify: {
                collapseWhitespace: true, //折叠空白区域
                removeComments: true, //删除注释
                hash: true, //是否需要对src引的文件后面加上Hash,使用时需要区分开发环境和生产环境
                chunks: [], //允许添加一些额外的文件
                chunksSortMode: 'manual' //chunks的文件顺序注入
            }
        }),
    ]
};
  1. 执行打包命令npm run build,dist文件夹下生成了index.html,运行即可看到Hello World

四、 编译css

开发时,css都是单独的文件,我们姑且这样做

  1. vue-demo/src下创建common.css,将index.html中的style移植过来,为了区分,改一下颜色
// vue-demo/src/common.css
body{
    background-color: #fff;
    color: red;
}
// vue-demo/index.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
        <title>vue&&webpack</title>
        <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
	</head>
	<body>
        <div id="app">
            <h1>Hello World</h1>
        </div>
	</body>
</html>
  1. 修改main.js,引人css
// vue-demo/src/main.js
import './common.css'

此时执行打包命令,会报错,这是因为webpack只能处理js和json代码,处理其他代码则需要借助loader
4. 安装处理css需要的loader,执行npm install css-loader style-loader -D
5. 配置loader,修改webpack.config.js

// vue-demo/webpack.config.js 新增
module: {
    rules: [{
        test: /\.css$/,
        use: [
            'style-loader',
            'css-loader'
        ]
    }]
}

注意加载顺序,此处style-loader必须在css-loader之前,否则会报错,你可以试一下
6. 执行打包命令,运行打包后的html文件,可以看到白色背景红色字体,即为成功

五、 热更新

提醒:修改各种配置文件或者安装插件时,先把项目停止,以免发生不可预期的错误

  1. 在集成vue之前,先实现热更新的功能,免得每次都要打包查看结果,安装插件npm install webpack-dev-server -D
  2. 修改webpack.config.js
// vue-demo/webpack.config.js 新增
devServer: {
    contentBase: path.join(__dirname, 'dist'), // 服务器资源的根目录,不写的话,默认为bundle.js
    hot: true, //启用热加载
    host: 'localhost',
    port: 5000, //端口号
    compress: true, // 服务器资源采用gzip压缩
    open: true, // 服务器启动后打开默认浏览器
    historyApiFallback: true, // 解决history模式刷新404
}

提醒:historyApiFallback是解决本地history刷新页面404的配置,线上是使用nginx配置解决
3. 修改package.json文件

// vue-demo/package.json 修改
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack serve --mode development",
    "build": "webpack --mode production"
}

提醒:以前的写法是"dev": "webpack-dev-serve --mode development",现在已变更为"dev": "webpack serve --mode development",这个耽误了我不少查找时间,这里做个记录
4. 执行npm run dev,不出意外,项目会自动打开了。(是不是跟vue脚手架有一点像了)

六、 集成Vue

上面的操作跟vue没有任何关系,现在请主角登场

  1. 安装vue,执行npm install vue
  2. 修改main.js
// vue-demo/src/main.js 看一下控制台是否打印成功
import Vue from 'vue'
import './common.css'
console.log(Vue);
  1. 创建App.vue入口文件(vue-cli创建的项目是不是也有一个这个东西?这里还原他)
// vue-demo/src/App.vue 将main.js里引入css的代码去掉,在这里引入,保持main.js的整洁
<template>
    <div>
        <h1>{{ text }}</h1>
    </div>
</template>
<script>
export default {
    data() {
        return {
            text: '你好,世界'
        }
    },
    methods: {
        
    },
}
</script>
<style>
@import url("./common.css");
</style>
  1. 创建vue实例
// vue-demo/src/main.js 看一下控制台是否打印成功
import Vue from 'vue'
import './common.css'
console.log(Vue);
new Vue({
    render: (h) => {
        return h(App)
    }
}).$mount("#app")
  1. 重新启动项目,出乎意料的是报错了,“你好,世界”也没有显示出来报错如下:Uncaught Error: Module parse failed: Unexpected token (1:0) You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file大致意思是我们确实处理vue的loader,当然了,前面说过,webpack默认只认识js和json,所有这里我们要给他赋能
  2. 安装vue-loader,修改配置,执行npm install vue-loader vue-template-compiler -D,为什么是两个,具体可以上官网查看
// vue-demo/webpack.config.js 修改
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader');
module.exports = {
    entry: './src/main.js', // 入口文件
    output: { // 输出
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
    },
    plugins: [
        new HtmlWebpackPlugin({
            template: './index.html',
            minify: {
                collapseWhitespace: true, //折叠空白区域
                removeComments: true, //删除注释
                hash: true, //是否需要对src引的文件后面加上Hash,使用时需要区分开发环境和生产环境
                chunks: [], //允许添加一些额外的文件
                chunksSortMode: 'manual' //chunks的文件顺序注入
            }
        }),
        new VueLoaderPlugin()
    ],
    module: {
        rules: [{
            test: /\.css/,
            use: [
                'style-loader',
                'css-loader'
            ]
        },{
            test: /\.vue$/,
            use: [
                'vue-loader'
            ]
        }]
    },
    devServer: {
        contentBase: path.join(__dirname, 'dist'), // 服务器资源的根目录,不写的话,默认为bundle.js
        hot: true, //启用热加载
        host: 'localhost',
        port: 5000, //端口号
        compress: true, // 服务器资源采用gzip压缩
        open: true, // 服务器启动后打开默认浏览器
        historyApiFallback: true, // 解决history模式刷新404
    }
};
  1. 运行项目npm run dev,红色的“你好,世界”出来了吧,看到有一个英文闪一下,删掉idnex.html #ppp 里的内容

七、 集成scss

这个跟vue-cli项目一样的集成方式,这里再来一遍

  1. 安装,执行npm install node-sass sass-loader -D,修改webpack.config.js
// vue-demo/webpack.config.js module新增
{
    test: /\.scss$/,
    use: [
        'style-loader',
        'css-loader',
        'sass-loader'
    ]
}

至此,此项目的webpack配置文件我们配置完了,如需其他配置可上官网查看
2. 将vue-demo/src/common.css改为common.scss,App.vue引用也改成@import url("./common.scss")

// vue-demo/src/App.vue
<template>
    <div>
        <h1>{{ text }}</h1>
    </div>
</template>
<script>
export default {
    data() {
        return {
            text: '你好,世界'
        }
    },
    methods: {
        click() {
            this.lang = this.lang === 'ch' ? 'en' : 'ch'
        }
    },
}
</script>
<style lang="scss">
@import url("./common.scss");
</style>
  1. 启动项目,不报错且能看到红色字体,则说明scss集成成功

八、 集成vue-router

  1. 安装vue-router,npm install vue-router
  2. vue-demo/src下创建pages目录,并在pages下创建4个vue页面,分别命名为pageA、pageB、pageC、pageD
// vue-demo/src/pages/pageA  其他页面跟这个一样,只是h1里的内容不一样
<template>
    <div>
        <h1>pageA</h1>
    </div>
</template>
<script>
    export default {
        data() {
            return {

            }
        },
        methods: {

        }
    }
</script>
<style lang="scss" scoped>
</style>
  1. vue-demo/src下创建route文件夹,并在route下创建index.js,作为路由配置文件
// vue-demo/src/route/index.js 其中配置了路由及子路由
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
export default new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/', 
            redirect: { name: 'pageA' },
        },
        {
            name: 'pageA',
            path: '/pageA', 
            component: () => import('../pages/pageA.vue'), 
            children: [
                {
                    name: 'pageB',
                    path: 'pageB', 
                    component: () => import('../pages/pageB.vue')
                },
                {
                    name: 'pageC',
                    path: 'pageC', 
                    component: () => import('../pages/pageC.vue')
                }
            ]
        },
        {
            name: 'pageD',
            path: '/pageD', 
            component: () => import('../pages/pageD.vue')
        }
    ]
})
  1. main.js注入vue,并启动项目,此时浏览器为http://localhost:5000/pageA,恭喜,路由集成成功
// vue-demo/src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
new Vue({
    router,
    render: (h) => {
        return h(App)
    }
}).$mount("#app")
  1. 接下来验证一下子路由,修改pageA
// vue-demo/src/pages/pageA
<template>
    <div>
        <h1>我是index页面</h1>
        <a @click="changeRoute('pageB')">跳转pageB子路由</a>
        <a @click="changeRoute('pageC')">跳转pageC子路由</a>
        <router-view></router-view>
    </div>
</template>
<script>
    export default {
        data() {
            return {

            }
        },
        methods: {
            changeRoute(name) {
                this.$router.push({name})
            }
        }
    }
</script>
<style lang="scss" scoped>
a{
    color: #169DFA;
    margin-right: 20px;
}
</style>

点击子路由按钮,分别跳转到不同路由,页面也有变化,恭喜,子路由也没有问题

九、 集成vuex

为了验证vuex,在vue-demo/src下新建一个components目录,熟悉vue的知道接下来要干嘛了,没错,创建公共组件

  1. vue-demo/src/components下创建Footer.vue
// vue-demo/src/components/Footer.vue
<template>
    <div class="footer">
        <div>
            <div @click="changeRoute('pageA')">pageA</div>
            <div @click="changeRoute('pageD')">pageD</div>
        </div>
    </div>
</template>
<script>
    export default {
        data() {
            return {

            }
        },
        methods: {
            changeRoute(name) {
                this.$router.replace({name})
            }
        }
    }
</script>
<style lang="scss" scoped>
.footer{
    width: 100vw;
    height: 50px;
    &>div{
        position: fixed;
        z-index: 1;
        left: 0;
        bottom: 0;
        width: 100vw;
        height: 50px;
        background-color: #fff;
        display: flex;
        align-items: center;
        justify-content: space-between;
        border-top: 1px solid #ddd;
        &>div{
            display: flex;
            align-items: center;
            justify-content: center;
            flex: 1;
            height: 100%;
        }
    }
}
</style>
  1. 在App.vue引用组件
<template>
    <div>
        <h1>{{ text }}</h1>
        <router-view></router-view>
        <Footer/>
    </div>
</template>
<script>
import Footer from './components/Footer.vue'
export default {
    components: {
        Footer
    },
    data() {
        return {
            text: '你好,世界'
        }
    },
    methods: {
        
    },
}
</script>
<style lang="scss">
@import url("./common.scss");
</style>

此时已经可以切换pageA、pageB、pageC、pageD四个路由了,接下来集成vuex

  1. 安装vuex,npm isntall vuex
  2. vue-demo/src下新建store文件夹,并在store下新建index.js作为vuex配置
vue-demo/src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})

这里store我们使用官方案例,做一个计数器功能
5. main.js注入vuex

vue-demo/src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './route'
import store from './store'
new Vue({
    router,
    store,
    render: (h) => {
        return h(App)
    }
}).$mount("#app")
  1. 验证vuex,在pageA、pageD中分别加入验证的代码
//pageA
<template>
    <div>
        <h1>我是index页面</h1>
        <a @click="changeRoute('pageB')">跳转pageB子路由</a>
        <a @click="changeRoute('pageC')">跳转pageC子路由</a>
        <router-view></router-view>
        <button @click="add">加1</button>
        <h2>vuex共享数据计数器的值:{{count}}</h2>
    </div>
</template>
<script>
    export default {
        computed: {
            count() {
                return this.$store.state.count
            }
        },
        methods: {
            changeRoute(name) {
                this.$router.push({name})
            },
            add(){
                this.$store.commit('increment')
            }
        }
    }
</script>
<style lang="scss" scoped>
a{
    color: #169DFA;
    margin-right: 20px;
}
</style>
// pageD
<template>
    <div>
        <h1>pageD</h1>
        <button @click="add">加1</button>
        <h2>vuex共享数据计数器的值:{{count}}</h2>
    </div>
</template>
<script>
    export default {
        computed: {
            count() {
                return this.$store.state.count
            }
        },
        methods: {
            add(){
                this.$store.commit('increment')
            }
        }
    }
</script>

此时在apgeA和pageD中点击按钮,无论切换到另外哪个路由,可以看到计数器的值已经实现共享了,至此vuex集成完毕

一个简单vue项目诞生了,完毕!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值