从零开始:一个正式的vue+webpack项目的目录结构是怎么造成的

如何从零开始一个vue+webpack前端工程工做流的搭建,首先咱们先从项目的目录结构入手。一个持续可发展,不断加入新功能,方便后期维护的目录结构到底是长什么样子的?接下来闰土大叔带大家一块儿手摸手学起来。css

初级前端初始化目录篇

项目伊始,咱们确定是先在terminal终端命令行(如下简称terminal)cd进入<project name>根目录,而后输入 npm init 初始化一个npm项目,在项目根目录下面就会出现一个package.json文件。
而后就能够安装依赖了,直接在terminal里输入 npm i webpack vue vue-loader -D。当咱们把这几个安装好之后,terminal这边会提示咱们WARN(警告⚠️):html

clipboard.png

翻译过来大意是,vue-loader须要一个css-loader和vue-template-compiler做为它的第三方依赖,因此听它的话,咱们去进行一下安装:前端

npm i css-loader vue-template-compiler -Dvue

那下面的警告信息提示咱们缺乏一些信息,这个其实无关痛痒,因此不须要去关心它。node

经过以上简单几个步骤,咱们的项目就初始化好了。而后在根目录下面建立一个src文件夹,这是咱们源码放置的目录。而后咱们在src目录下面新建一个app.vue文件,里面就能够写一些关于项目的业务代码:webpack

<template>
    <div id="test">{{text}}</div>
</template>
<script>
    export default {
        data () {
            text: '闰土大叔'
        }
    }
</script>
<style>
#test{
    font-size:12px;
    color:green;
}
</style>

固然这个后缀为.vue 文件是不能够在浏览器里直接运行的,咱们须要想办法让它运行起来。web

如今咱们要在项目根目录下新建一个webpack.config.js文件,webpack是帮咱们前端来打包资源的,前端资源有不少不一样的类型,好比说JavaScript,css,html,image,iconfont等这些资源都是须要经过http请求加载的东西。webpack是将一个js文件加载到浏览器端以后,而后去把全部的内容去渲染出来。因此,不少时候,咱们能够把js文件做为项目的入口文件。面试

这个时候,咱们在src目录下新建一个index.js做为入口文件,顺便在里面写点东西:npm

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)

index.js准备完毕以后,那么在webpack.config.js里面就能够这样写:json

const path = require('path')

module.exports = {
    entry:  path.join(__dirname, 'src/index.js'),
    output: {
        filename: 'bundle.js',
        path: path.join(__dirname, 'dist')
    }
}

在上面的代码中,__dirname就表明这个文件所在的目录地址,path.join()的意思就是和后面的字符串路径拼接起来,造成一个绝对的路径。

而后经过webpack把全部的文件打包成一个bundle.js文件,而且是能在浏览器里面直接运行的代码。如今咱们能够在package.json 文件里的scripts对象里面添加一个脚本:

"scripts": {
    "build": "webpack --config webpack.config.js"
}

看到这儿,确定有童鞋要问了,为何要在这里面调用webpack而不是在terminal里面直接运行呢?

由于只有在这里调用webpack,它才会优先调用咱们项目里面安装的webpack版本,若是咱们在命令行里面输入webpack,它会调动全局的webpack,这个时候全局的webpack可能会跟咱们项目中的webpack版本不一致,因此咱们仍是采起这种方式比较稳妥。

写完以后,咱们就能够在terminal输入 npm run build 跑一下,会尴尬地发现报错了:

clipboard.png

这个错误告诉咱们,须要为.vue文件去声明一个loader。由于webpack原生是只支持JS文件类型的,而且只支持ES5的语法,因此咱们在使用超出它理解范围的语法的时候,咱们要使用一些帮它去处理的工具。因此咱们要在webpack.config.js文件里面继续写:

module: {
    rules: [
        {
            test: /.vue$/,
            loader: 'vue-loader'
        }
    ]
}

添加完这段以后,咱们再去terminal执行下npm run build,你会发现项目根目录下多了一个dist文件夹,点开里面发现webpack为咱们自动打包生成了一个bundle.js文件,感兴趣的童鞋能够点开这个js文件看看:

clipboard.png

它里面代码不少,上面是固有的webpack的代码,这些代码是处理项目中的模块依赖的,由于咱们项目里有不少的js相互依赖。

clipboard.png

往下翻到100多行左右的时候,你会发现有不少的代码实际上是vue源码。由于咱们项目要依赖vue.js,因此webpack会把vue.js文件打包进来。

clipboard.png

你能够经过快捷键 command (Ctrl) + F 查找关键词$mount看到,红线圈住的这段代码就是咱们本身写的代码,其实webpack作的工做就是把这些不一样的静态资源的类型打包成一个js,而后咱们在html里面引用这个js,就能够正常运行。

相信你们作前端都知道,在作一个项目开发的时候,咱们但愿把一些零碎的js文件打包到一块儿,这样能够减小http请求。一样的,咱们但愿使用模块依赖,由于项目中会作不少可复用的代码,把它写到一个模块里面去,这样的话当咱们再去写一个新项目的时候,不用再把原来的代码从新写一遍,或者是拷贝一份。

固然这里面咱们暂时没有提到.babelrc、.eslintrc、editorconfig、postcss.config.js等,这些咱们留到后面再讲。

中级前端合理细化目录篇

clipboard.png

初始化工做完成以后,接下来咱们要细分目录了。首先咱们须要在项目的根目录下新建一个文件夹叫build,把webpack的文件单独放到这个文件夹里面。由于咱们项目中会用到不少不一样的相关文件的配置,接下来先新建一个 webpack.config.base.js 文件,咱们把webpack里面须要用到的共同的配置放到这个base的文件里面。好比开发环境和正式环境,以及后期咱们要提到的服务端渲染的环境。咱们都依赖于base这个配置。

如下是webpack.config.base.js文件里的代码:

const path = require('path')
const createVueLoaderOptions = require('./vue-loader.config')

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

const config = {
  target: 'web',
  entry: path.join(__dirname, '../client/index.js'),
  output: {
    filename: 'bundle.[hash:8].js',
    path: path.join(__dirname, '../dist')
  },
  module: {
    rules: [
      {
        test: /\.(vue|js|jsx)$/,
        loader: 'eslint-loader',
        exclude: /node_modules/,
        enforce: 'pre'
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: createVueLoaderOptions(isDev)
      },
      {
        test: /\.jsx$/,
        loader: 'babel-loader'
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/
      },
      {
        test: /\.(gif|jpg|jpeg|png|svg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 1024,
              name: 'resources/[path][name].[hash:8].[ext]'
            }
          }
        ]
      }
    ]
  }
}

module.exports = config

而后咱们再新建一个 webpack.config.client.js ,这个client文件依赖于base文件,在此基础上扩展一些其余配置。所以咱们须要在webpack.config.client.js里面敲入一行代码引入base文件 :

const baseConfig = require('./webpack.config.base')

基础工做作完以后,咱们该如何去扩展配置呢?首先在terminal终端命令行安装下 npm i webpack-merge -D 咱们须要webpack-merge这个工具帮助去扩展、合并不一样的webpack配置,而后根据声明好的isDev来判断应该怎么合并配置。

如下是webpack.config.client.js文件里的代码:

const path = require('path')
const HTMLPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const merge = require('webpack-merge')
const ExtractPlugin = require('extract-text-webpack-plugin')
const baseConfig = require('./webpack.config.base')

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

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

const devServer = {
  port: 8000,
  host: '0.0.0.0',
  overlay: {
    errors: true
  },
  hot: true
}

let config

if (isDev) {
  // 开发环境的配置
  config = merge(baseConfig, {
    devtool: '#cheap-module-eval-source-map',
    module: {
      rules: [
        {
          test: /\.styl/,
          use: [
            'vue-style-loader',
            'css-loader',
            // {
            //   loader: 'css-loader',
            //   options: {
            //     module: true,
            //     localIdentName: isDev ? '[path]-[name]-[hash:base64:5]' : '[hash:base64:5]'
            //   }
            // },
            {
              loader: 'postcss-loader',
              options: {
                sourceMap: true
              }
            },
            'stylus-loader'
          ]
        }
      ]
    },
    devServer,
    plugins: defaultPlugins.concat([
      new webpack.HotModuleReplacementPlugin(),
      new webpack.NoEmitOnErrorsPlugin()
    ])
  })
} else {
  // 正式环境的配置
  config = merge(baseConfig, {
    entry: {
      app: path.join(__dirname, '../client/index.js'),
      vendor: ['vue']
    },
    output: {
      filename: '[name].[chunkhash:8].js'
    },
    module: {
      rules: [
        {
          test: /\.styl/,
          use: ExtractPlugin.extract({
            fallback: 'vue-style-loader',
            use: [
              'css-loader',
              {
                loader: 'postcss-loader',
                options: {
                  sourceMap: true
                }
              },
              'stylus-loader'
            ]
          })
        }
      ]
    },
    plugins: defaultPlugins.concat([
      new ExtractPlugin('styles.[contentHash:8].css'),
      new webpack.optimize.CommonsChunkPlugin({
        name: 'vendor'
      }),
      new webpack.optimize.CommonsChunkPlugin({
        name: 'runtime'
      })
    ])
  })
}

module.exports = config

最后,这个src文件夹咱们要重命名一下,叫client,由于咱们后期还要写服务端的代码,对应的就命名成server,正好对应它的含义。这样看起来,名称就变得更加的合理。

当咱们万事大吉的时候,千万记得要把 webpack.config.base.js 和 webpack.config.client.js 里面的src路径改掉,换成client,不然就会报错。

clipboard.png

以上就是咱们项目最终造成的目录结构,client目录下分别有assets、layout、views这三个文件夹,其中assets目录下放静态资源,例如images、styles等;layout目录下放通用布局的组件;views目录下放具体的业务代码的组件。

固然,这个目录其实还能够随着项目的开发再细分下去,这里就不展开叙述了。

写在最后

你们必定要注意,在咱们正式开发项目、建立一个项目工程的时候,必定要先把目录结构理顺,条理必定要清楚。每一个目录结构里面放什么东西,内心必定要先有个概念。之后新建的文件不要乱放,由于项目一旦作大,维护时间比较久的时候,可能两三个月里面都有一个文件你不会去碰它。到时候若是要去找一个东西的时候,你会找不到它,这是很是使人难受的一件事情。

最重要的一点是,目录结构的混乱,会致使你后续开发项目的效率变得很是的低。

此次关于“一个正式项目的目录结构是怎么造成的”的话题就说到这里,我以后的文章会讲些什么呢?文章预告以下:

  • eslint的错误修复小技巧
  • vue-loader是如何配置的
  • 如何回答“对vue生命周期的理解”才能让面试官满意?
  • 浅谈css-module的配置
  • ......
  • 正式环境打包以及异步模块打包优化

以上内容均会第一时间发布在个人公众号:闰土大叔 ,欢迎关注。

图片描述

相关文章
相关标签/搜索