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

初级前端初始化目录篇

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

翻译过来大意是,vue-loader需要一个css-loader和vue-template-compiler作为它的第三方依赖,所以听它的话,我们去进行一下安装:

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

那下面的警告信息提示我们缺少一些信息,这个其实无关痛痒,所以不需要去关心它。

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

  1. <template>
  2. <div id="test">{{text}}</div>
  3. </template>
  4. <script>
  5. export default {
  6. data () {
  7. text: '闰土大叔'
  8. }
  9. }
  10. </script>
  11. <style>
  12. #test{
  13. font-size:12px;
  14. color:green;
  15. }
  16. </style>

当然这个后缀为.vue 文件是不可以在浏览器里直接运行的,我们需要想办法让它运行起来。

现在我们要在项目根目录下新建一个webpack.config.js文件,webpack是帮我们前端来打包资源的,前端资源有很多不同的类型,比如说JavaScript,css,html,image,iconfont等这些资源都是需要通过http请求加载的东西。webpack是将一个js文件加载到浏览器端之后,然后去把所有的内容去渲染出来。所以,很多时候,我们可以把js文件作为项目的入口文件。

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

  1. import Vue from 'vue'
  2. import App from './app.vue'
  3. const root = document.createElement('div')
  4. document.body.appendChild(root)
  5. new Vue({
  6. render: (h) => h(App)
  7. }).$mount(root)

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

  1. const path = require('path')
  2. module.exports = {
  3. entry: path.join(__dirname, 'src/index.js'),
  4. output: {
  5. filename: 'bundle.js',
  6. path: path.join(__dirname, 'dist')
  7. }
  8. }

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

然后通过webpack把所有的文件打包成一个bundle.js文件,并且是能在浏览器里面直接运行的代码。现在我们可以在package.json 文件里的scripts对象里面添加一个脚本:

  1. "scripts": {
  2. "build": "webpack --config webpack.config.js"
  3. }

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

因为只有在这里调用webpack,它才会优先调用我们项目里面安装的webpack版本,如果我们在命令行里面输入webpack,它会调动全局的webpack,这个时候全局的webpack可能会跟我们项目中的webpack版本不一致,所以我们还是采取这种方式比较稳妥。

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

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

  1. module: {
  2. rules: [
  3. {
  4. test: /.vue$/,
  5. loader: 'vue-loader'
  6. }
  7. ]
  8. }

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

 
 
它里面代码很多,上面是固有的webpack的代码,这些代码是处理项目中的模块依赖的,因为我们项目里有很多的js相互依赖。

往下翻到100多行左右的时候,你会发现有很多的代码其实是vue源码。因为我们项目要依赖vue.js,所以webpack会把vue.js文件打包进来。

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

相信大家做前端都知道,在做一个项目开发的时候,我们希望把一些零碎的js文件打包到一起,这样可以减少http请求。同样的,我们希望使用模块依赖,因为项目中会做很多可复用的代码,把它写到一个模块里面去,这样的话当我们再去写一个新项目的时候,不用再把原来的代码重新写一遍,或者是拷贝一份。

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

中级前端合理细化目录篇

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

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

  1. const path = require('path')
  2. const createVueLoaderOptions = require('./vue-loader.config')
  3. const isDev = process.env.NODE_ENV === 'development'
  4. const config = {
  5. target: 'web',
  6. entry: path.join(__dirname, '../client/index.js'),
  7. output: {
  8. filename: 'bundle.[hash:8].js',
  9. path: path.join(__dirname, '../dist')
  10. },
  11. module: {
  12. rules: [
  13. {
  14. test: /\.(vue|js|jsx)$/,
  15. loader: 'eslint-loader',
  16. exclude: /node_modules/,
  17. enforce: 'pre'
  18. },
  19. {
  20. test: /\.vue$/,
  21. loader: 'vue-loader',
  22. options: createVueLoaderOptions(isDev)
  23. },
  24. {
  25. test: /\.jsx$/,
  26. loader: 'babel-loader'
  27. },
  28. {
  29. test: /\.js$/,
  30. loader: 'babel-loader',
  31. exclude: /node_modules/
  32. },
  33. {
  34. test: /\.(gif|jpg|jpeg|png|svg)$/,
  35. use: [
  36. {
  37. loader: 'url-loader',
  38. options: {
  39. limit: 1024,
  40. name: 'resources/[path][name].[hash:8].[ext]'
  41. }
  42. }
  43. ]
  44. }
  45. ]
  46. }
  47. }
  48. 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文件里的代码:

  1. const path = require('path')
  2. const HTMLPlugin = require('html-webpack-plugin')
  3. const webpack = require('webpack')
  4. const merge = require('webpack-merge')
  5. const ExtractPlugin = require('extract-text-webpack-plugin')
  6. const baseConfig = require('./webpack.config.base')
  7. const isDev = process.env.NODE_ENV === 'development'
  8. const defaultPlugins = [
  9. new webpack.DefinePlugin({
  10. 'process.env': {
  11. NODE_ENV: isDev ? '"development"' : '"production"'
  12. }
  13. }),
  14. new HTMLPlugin()
  15. ]
  16. const devServer = {
  17. port: 8000,
  18. host: '0.0.0.0',
  19. overlay: {
  20. errors: true
  21. },
  22. hot: true
  23. }
  24. let config
  25. if (isDev) {
  26. // 开发环境的配置
  27. config = merge(baseConfig, {
  28. devtool: '#cheap-module-eval-source-map',
  29. module: {
  30. rules: [
  31. {
  32. test: /\.styl/,
  33. use: [
  34. 'vue-style-loader',
  35. 'css-loader',
  36. // {
  37. // loader: 'css-loader',
  38. // options: {
  39. // module: true,
  40. // localIdentName: isDev ? '[path]-[name]-[hash:base64:5]' : '[hash:base64:5]'
  41. // }
  42. // },
  43. {
  44. loader: 'postcss-loader',
  45. options: {
  46. sourceMap: true
  47. }
  48. },
  49. 'stylus-loader'
  50. ]
  51. }
  52. ]
  53. },
  54. devServer,
  55. plugins: defaultPlugins.concat([
  56. new webpack.HotModuleReplacementPlugin(),
  57. new webpack.NoEmitOnErrorsPlugin()
  58. ])
  59. })
  60. } else {
  61. // 正式环境的配置
  62. config = merge(baseConfig, {
  63. entry: {
  64. app: path.join(__dirname, '../client/index.js'),
  65. vendor: ['vue']
  66. },
  67. output: {
  68. filename: '[name].[chunkhash:8].js'
  69. },
  70. module: {
  71. rules: [
  72. {
  73. test: /\.styl/,
  74. use: ExtractPlugin.extract({
  75. fallback: 'vue-style-loader',
  76. use: [
  77. 'css-loader',
  78. {
  79. loader: 'postcss-loader',
  80. options: {
  81. sourceMap: true
  82. }
  83. },
  84. 'stylus-loader'
  85. ]
  86. })
  87. }
  88. ]
  89. },
  90. plugins: defaultPlugins.concat([
  91. new ExtractPlugin('styles.[contentHash:8].css'),
  92. new webpack.optimize.CommonsChunkPlugin({
  93. name: 'vendor'
  94. }),
  95. new webpack.optimize.CommonsChunkPlugin({
  96. name: 'runtime'
  97. })
  98. ])
  99. })
  100. }
  101. module.exports = config

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

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

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

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

写在最后

大家一定要注意,在我们正式开发项目、创建一个项目工程的时候,一定要先把目录结构理顺,条理一定要清楚。每个目录结构里面放什么东西,心里一定要先有个概念。以后新建的文件不要乱放,因为项目一旦做大,维护时间比较久的时候,可能两三个月里面都有一个文件你不会去碰它。到时候如果要去找一个东西的时候,你会找不到它,这是非常令人难受的一件事情。

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

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

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

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

从零开始:一个正式的vue+webpack项目的目录结构是怎么形成的的更多相关文章

  1. 怎样理解 Vue 项目的目录结构?

      Vue 项目的目录结构如下, 我们将会在后面逐个去了解它们的作用: 01. build - 存储项目构建相关的代码, 比如 webpack. 02. config - Vue 的配置目录,包括端口 ...

  2. Android开发系列之Android项目的目录结构

    今天开始正式学习Android开发的种种细节,首先从最基本的概念和操作学起. 首先看一下Android项目的目录结构. 这是我随便建立的一个test项目,我们重点关注一下几个方面的内容: 1.src目 ...

  3. AngularJS+requireJS项目的目录结构设想

    AngularJS+requireJS项目的目录结构设想 准备用AngularJS + require.js 作为新项目的底层框架,以下目录结果只是一个初步设想: /default    放页面,不过 ...

  4. vue-cli搭建项目的目录结构及说明

    vue-cli基于webpack搭建项目的目录结构 build文件夹 ├── build              // 项目构建的(webpack)相关代码    │ ├── build.js   ...

  5. Go 项目的目录结构 及 安装技巧

    项目目录结构如何组织,一般语言都是没有规定.但 Go 语言这方面做了规定,这样可以保持一致性 1.一般的,一个 Go 项目在 GOPATH 下,会有如下三个目录: |--bin |--pkg |--s ...

  6. Android开发学习——Android项目的目录结构

    Android项目的目录结构: 资源文件夹: 清单配置文件: Android的四大组件在使用前全部需要在清单文件中配置 <?xml version="1.0" encodin ...

  7. Maven项目的目录结构+maven的安装与配置

    1.首先下载maven,然后配置环境变量,在MyEclipse里面配置maven 2.配置maven的pom.xml文件 3.下载和更新资源 右击项目,有一个Maven4Myeclipse,里面有三个 ...

  8. ASP.NET MVC 入门2、项目的目录结构与核心的DLL

    我们新建一个ASP.NET MVC的Web Application后,默认的情况下,项目的目录结构如下: App_Data :这个目录跟我们一般的ASP.NET website是一样的,用于存放数据. ...

  9. [转]ASP.NET MVC 入门2、项目的目录结构与核心的DLL

    我们新建一个ASP.NET MVC的Web Application后,默认的情况下,项目的目录结构如下: App_Data :这个目录跟我们一般的ASP.NET website是一样的,用于存放数据. ...

随机推荐

  1. MySQL DBA教程全套视频资料

    MySQL基础入门.MySQL多实例安装与企业应用场景.MySQL应用管理及进阶实战操作.MySQL乱码问题及字符集实战.MySQL备份-增量备份及数据恢复基础实战.MySQL主从复制原理及实战部署. ...

  2. 浅析C#之委托、Action、Func

    一.委托 1.1 委托的定义 delegate(委托)是一种可用于封装命名方法或匿名方法的引用类型, 委托类似于 C++ 中的函数指针: .Net通过委托来提供回调函数机制. 声明一个委托类型 int ...

  3. 元组tuple基本操作

    创建一个元组 tuple1=(1,2,3,4,5,6,7,8) tuple的标志仿佛是(),但是,有()不一定是元组,没有()不一定不是元组 tuple2=(1)#tuple2是一个整型 tuple3 ...

  4. Jmeter4.0----安装教程(2)

    1.检查安装环境 1.1 JDK要求 JDK版本:1.6 + 1.2 检查是否安装JDK win + R 快捷键打开运行,输入 cmd 打开面板,在面板中输入 java -version,出现如下信息 ...

  5. RabbitMQ 通信过程

    Rabbit MQ的通信过程 MQ全称为Message Queue, 是一种分布式应用程序的的通信方法,是消费-生产者模型的典型的代表,producer往消息队列中不断写入消息,而另一端consume ...

  6. 慢查询日志分析(mysql)

    开启慢查询日志之后,慢查询sql会被存到数据库系统表mysql.slow_log或是文件中,可参考.有两个工具可以帮助我们分析输出报告,分别是mysqldumpslow和pt-query-digest ...

  7. Struts2——第一个helloworld页面

    struts2是一个较为成熟的mvc框架,先看看怎么配置struts2并且产生helloworld页面. 首先从官网下载struts2,http://struts.apache.org/downloa ...

  8. Beta阶段敏捷冲刺报告-DAY1

    Beta阶段敏捷冲刺报告-DAY1 Scrum Meeting 敏捷开发日期 2017.11.2 讨论时间 20:30 讨论地点 下课路上以及院楼侧门 参会人员 项目组全体成员 会议内容 附加功能讨论 ...

  9. 基于微信小程序的失物招领系统的Postmortem

    基于微信小程序的失物招领系统的Postmortem 设想和目标 1.我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 对于我们团队要解决的问题和实现的功能在项目开始就 ...

  10. 201621123043 《Java程序设计》第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 泛型的定义: 泛型,即"参数化类型".一提到参数,最熟悉的就是定义方法时有形参,然后调用此 ...