摘要:一个持续可发展,不断加入新功能,方便后期维护的目录结构究竟是长什么样子的接下来闰土大叔带你们一起手摸手学起来。
如何从零开始一个vue+webpack前端工程工作流的搭建,首先我们先从项目的目录结构入手。一个持续可发展,不断加入新功能,方便后期维护的目录结构究竟是长什么样子的?接下来闰土大叔带你们一起手摸手学起来。
初级前端初始化目录篇项目伊始,我们肯定是先在terminal终端命令行(以下简称terminal)cd进入
然后就可以安装依赖了,直接在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文件,里面就可以写一些关于项目的业务代码:
{{text}}
当然这个后缀为.vue 文件是不可以在浏览器里直接运行的,我们需要想办法让它运行起来。
现在我们要在项目根目录下新建一个webpack.config.js文件,webpack是帮我们前端来打包资源的,前端资源有很多不同的类型,比如说JavaScript,css,html,image,iconfont等这些资源都是需要通过http请求加载的东西。webpack是将一个js文件加载到浏览器端之后,然后去把所有的内容去渲染出来。所以,很多时候,我们可以把js文件作为项目的入口文件。
这个时候,我们在src目录下新建一个index.js作为入口文件,顺便在里面写点东西:
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里面就可以这样写:
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 跑一下,会尴尬地发现报错了:
这个错误告诉我们,需要为.vue文件去声明一个loader。因为webpack原生是只支持JS文件类型的,并且只支持ES5的语法,所以我们在使用超出它理解范围的语法的时候,我们要使用一些帮它去处理的工具。所以我们要在webpack.config.js文件里面继续写:
module: { rules: [ { test: /.vue$/, loader: "vue-loader" } ] }
添加完这段之后,我们再去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文件里的代码:
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,否则就会报错。
以上就是我们项目最终形成的目录结构,client目录下分别有assets、layout、views这三个文件夹,其中assets目录下放静态资源,例如images、styles等;layout目录下放通用布局的组件;views目录下放具体的业务代码的组件。
当然,这个目录其实还可以随着项目的开发再细分下去,这里就不展开叙述了。
写在最后大家一定要注意,在我们正式开发项目、创建一个项目工程的时候,一定要先把目录结构理顺,条理一定要清楚。每个目录结构里面放什么东西,心里一定要先有个概念。以后新建的文件不要乱放,因为项目一旦做大,维护时间比较久的时候,可能两三个月里面都有一个文件你不会去碰它。到时候如果要去找一个东西的时候,你会找不到它,这是非常令人难受的一件事情。
最重要的一点是,目录结构的混乱,会导致你后续开发项目的效率变得非常的低。
这次关于“一个正式项目的目录结构是怎么形成的”的话题就说到这里,我之后的文章会讲些什么呢?文章预告如下:
eslint的错误修复小技巧
vue-loader是如何配置的
如何回答“对vue生命周期的理解”才能让面试官满意?
浅谈css-module的配置
......
正式环境打包以及异步模块打包优化
以上内容均会第一时间发布在我的公众号:闰土大叔 ,欢迎关注。文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/94168.html
摘要:后来经过排查你会发现是由于目前还没有版本。可以使用该方式解决。这就是我为什么不推荐你使用创建脚手架的原因此文的受众是想要进阶中级的初级前端人员。 最近在知乎看到一个问题,原问题如下: 很奇怪,为什么现在能找到自己手动创建vue脚手架的文章非常少,而且大家似乎对webpack4的热情并不高,对于想基于vue2.0+webpack4搭建一个脚手架的我来说资料真是少得可怜。难道现在一般的做...
摘要:各个大厂也相继宣布开源。但是也会存在一些问题,比如每个公司可能需要的业务组件不尽相同,或者我们想自己开发一套属于自己的组件库,来增强对组件的可控性。 前言: 前端组件化是当今热议的话题之一,也是我们在开发单页应用经常会碰到的一个问题,现在我们有了功能非常完善的Element-UI。各个大厂也相继宣布开源XXX-UI。但是也会存在一些问题,比如每个公司可能需要的业务组件不尽相同,或者我们...
摘要:各个大厂也相继宣布开源。但是也会存在一些问题,比如每个公司可能需要的业务组件不尽相同,或者我们想自己开发一套属于自己的组件库,来增强对组件的可控性。 前言: 前端组件化是当今热议的话题之一,也是我们在开发单页应用经常会碰到的一个问题,现在我们有了功能非常完善的Element-UI。各个大厂也相继宣布开源XXX-UI。但是也会存在一些问题,比如每个公司可能需要的业务组件不尽相同,或者我们...
摘要:它会检测出最大静态子树就是不需要动态性的子树并且从渲染函数中萃取出来。这样在每次重渲染的时候,它就会直接重用完全相同的同时跳过比对。需要注意的是,中的操作必须是同步的,不可以存在异步操作的情况。 新增:哈哈,最近又推出了 vue 的文章,在这里放个链接~手把手教你从零写一个简单的 VUE 感谢有人看我扯技术,这篇文章主要介绍最近非常火的vue2前端框架的特点和vue2+vuex2+we...
摘要:它会检测出最大静态子树就是不需要动态性的子树并且从渲染函数中萃取出来。这样在每次重渲染的时候,它就会直接重用完全相同的同时跳过比对。需要注意的是,中的操作必须是同步的,不可以存在异步操作的情况。 新增:哈哈,最近又推出了 vue 的文章,在这里放个链接~手把手教你从零写一个简单的 VUE 感谢有人看我扯技术,这篇文章主要介绍最近非常火的vue2前端框架的特点和vue2+vuex2+we...
阅读 3240·2021-10-13 09:39
阅读 2006·2021-09-27 13:36
阅读 3068·2021-09-22 16:02
阅读 2592·2021-09-10 10:51
阅读 1573·2019-08-29 17:15
阅读 1528·2019-08-29 16:14
阅读 3494·2019-08-26 11:55
阅读 2543·2019-08-26 11:50