>  기사  >  웹 프론트엔드  >  Vue 프로젝트 스캐폴딩 소개

Vue 프로젝트 스캐폴딩 소개

零下一度
零下一度원래의
2017-06-26 10:52:102240검색

github 주소 (간단한 예제 포함)

기술 스택 사용하기

  • webpack(^2.6.1)

  • webpack-dev-server(^2.4.5)

  • vue(^2.3.3 )

  • vuex(^2.3.1)

  • vue-router(^2.5.3)

  • vue-loader(^12.2.1)

  • eslint(^3.19.0)

당신이 배워야 할 것

vue.js
vuex
vue-router
vue-loader
webpack2
eslint


꽤 많은 콘텐츠가 있습니다. 특히 webpack2 튜토리얼은 공식 스캐폴딩 vue-입니다. cli는 꽤 완성되었으나, 아직 수정하는데 시간이 많이 걸리기 때문에 인터넷에 있는 정보와 이전 프로젝트에서 사용했던 구축 도구를 기반으로 간단한 Vue 프로젝트 스캐폴딩을 작성했습니다. 다중 페이지 스파 모드의 비즈니스 시나리오에 적합합니다(각 모듈은 스파임). 비교적 간단합니다. 주로 webpack.config.js 파일일 뿐입니다. 특별히 webpack.dev.config.js, webpack.prov.config.js 등의 구성 요소로 나누어져 있다고는 하지 않습니다. 다음은 전체 webpack.config.js 파일 코드입니다.

  1 const { resolve } = require('path')  2 const webpack = require('webpack')  3 const HtmlWebpackPlugin = require('html-webpack-plugin')  4 const ExtractTextPlugin = require('extract-text-webpack-plugin')  5 const glob = require('glob')  6   7 module.exports = (options = {}) => {  8     // 配置文件,根据 run script不同的config参数来调用不同config  9     const config = require('./config/' + (process.env.npm_config_config || options.config || 'dev')) 10     // 遍历入口文件,这里入口文件与模板文件名字保持一致,保证能同时合成HtmlWebpackPlugin数组和入口文件数组 11     const entries = glob.sync('./src/modules/*.js') 12     const entryJsList = {} 13     const entryHtmlList = [] 14     for (const path of entries) { 15         const chunkName = path.slice('./src/modules/'.length, -'.js'.length) 16         entryJsList[chunkName] = path 17         entryHtmlList.push(new HtmlWebpackPlugin({ 18             template: path.replace('.js', '.html'), 19             filename: 'modules/' + chunkName + '.html', 20             chunks: ['manifest', 'vendor', chunkName] 21         })) 22     } 23     // 处理开发环境和生产环境ExtractTextPlugin的使用情况 24     function cssLoaders(loader, opt) { 25         const loaders = loader.split('!') 26         const opts = opt || {} 27         if (options.dev) { 28             if (opts.extract) { 29                 return loader 30             } else { 31                 return loaders 32             } 33         } else { 34             const fallbackLoader = loaders.shift() 35             return ExtractTextPlugin.extract({ 36                 use: loaders, 37                 fallback: fallbackLoader 38             }) 39         } 40     } 41  42     const webpackObj = { 43         entry: Object.assign({ 44             vendor: ['vue', 'vuex', 'vue-router'] 45         }, entryJsList), 46         // 文件内容生成哈希值chunkhash,使用hash会更新所有文件 47         output: { 48             path: resolve(__dirname, 'dist'), 49             filename: options.dev ? 'static/js/[name].js' : 'static/js/[name].[chunkhash].js', 50             chunkFilename: 'static/js/[id].[chunkhash].js', 51             publicPath: config.publicPath 52         }, 53  54         externals: { 55  56         }, 57  58         module: { 59             rules: [ 60                 // 只 lint 本地 *.vue 文件,需要安装eslint-plugin-html,并配置eslintConfig(package.json) 61                 { 62                     enforce: 'pre', 63                     test: /.vue$/, 64                     loader: 'eslint-loader', 65                     exclude: /node_modules/ 66                 }, 67                 /* 68                      69                      70                     [eslint资料] 71                  */ 72                 { 73                     test: /\.js$/, 74                     exclude: /node_modules/, 75                     use: ['babel-loader', 'eslint-loader'] 76                 }, 77                 // 需要安装vue-template-compiler,不然编译报错 78                 { 79                     test: /\.vue$/, 80                     loader: 'vue-loader', 81                     options: { 82                         loaders: { 83                             sass: cssLoaders('vue-style-loader!css-loader!sass-loader', { extract: true }) 84                         } 85                     } 86                 }, 87                 { 88                     // 需要有相应的css-loader,因为第三方库可能会有文件 89                     // (如:element-ui) css在node_moudle 90                     // 生产环境才需要code抽离,不然的话,会使热重载失效 91                     test: /\.css$/, 92                     use: cssLoaders('style-loader!css-loader') 93                 }, 94                 { 95                     test: /\.(scss|sass)$/, 96                     use: cssLoaders('style-loader!css-loader!sass-loader') 97                 }, 98                 { 99                     test: /\.(png|jpg|jpeg|gif|eot|ttf|woff|woff2|svg|svgz)(\?.+)?$/,100                     use: [101                         {102                             loader: 'url-loader',103                             options: {104                                 limit: 10000,105                                 name: 'static/imgs/[name].[ext]?[hash]'106                             }107                         }108                     ]109                 }110             ]111         },112 113         plugins: [114             ...entryHtmlList,115             // 抽离css116             new ExtractTextPlugin({117                 filename: 'static/css/[name].[chunkhash].css',118                 allChunks: true119             }),120             // 抽离公共代码121             new webpack.optimize.CommonsChunkPlugin({122                 names: ['vendor', 'manifest']123             }),124             // 定义全局常量125             // cli命令行使用process.env.NODE_ENV不如期望效果,使用不了,所以需要使用DefinePlugin插件定义,定义形式'"development"'或JSON.stringify('development')126             new webpack.DefinePlugin({127                 'process.env': {128                     NODE_ENV: options.dev ? JSON.stringify('development') : JSON.stringify('production')129                 }130             })131 132         ],133 134         resolve: {135             // require时省略的扩展名,不再需要强制转入一个空字符串,如:require('module') 不需要module.js136             extensions: ['.js', '.json', '.vue', '.scss', '.css'],137             // require路径简化138             alias: {139                 '~': resolve(__dirname, 'src'),140                 // Vue 最早会打包生成三个文件,一个是 runtime only 的文件 vue.common.js,一个是 compiler only 的文件 compiler.js,一个是 runtime + compiler 的文件 vue.js。141                 // vue.js = vue.common.js + compiler.js,默认package.json的main是指向vue.common.js,而template 属性的使用一定要用compiler.js,因此需要在alias改变vue指向142                 vue: 'vue/dist/vue'143             },144             // 指定import从哪个目录开始查找145             modules: [146                 resolve(__dirname, 'src'),147                 'node_modules'148             ]149         },150         // 开启http服务,publicPath => 需要与Output保持一致 || proxy => 反向代理 || port => 端口号151         devServer: config.devServer ? {152             port: config.devServer.port,153             proxy: config.devServer.proxy,154             publicPath: config.publicPath,155             stats: { colors: true }156         } : undefined,157         // 屏蔽文件超过限制大小的warn158         performance: {159             hints: options.dev ? false : 'warning'160         },161         // 生成devtool,保证在浏览器可以看到源代码,生产环境设为false162         devtool: 'inline-source-map'163     }164 165     if (!options.dev) {166         webpackObj.devtool = false167         webpackObj.plugins = (webpackObj.plugins || []).concat([168             // 压缩js169             new webpack.optimize.UglifyJsPlugin({170                 // webpack2,默认为true,可以不用设置171                 compress: {172                     warnings: false173                 }174             }),175             //  压缩 loaders176             new webpack.LoaderOptionsPlugin({177                 minimize: true178             })179         ])180     }181 182     return webpackObj183 }

위 코드에는 각 구성 항목에 대한 주석이 있습니다. 여기서 주의할 점이 몇 가지 있습니다.

1. 함수입니다

이전 프로젝트의 webpack.config.js를 다음과 같이 객체 형태로 내보냈습니다

1 module.exports = {2     entry: ...,3     output: {4         ...5     },6     ...7 }

이제는 다음과 같은 함수입니다.

1 module.exports = (options = {}) => { 
2     return {3         entry: ...,4         output: {5             ...6         },7         ...8     }9 }

이 경우 , 함수는 webpack을 실행합니다. CLI 중에 webpack의 매개변수를 가져와 옵션을 통해 함수에 전달합니다. package.json을 살펴보세요.

1     "local": "npm run dev --config=local",2     "dev": "webpack-dev-server -d --hot --inline --env.dev --env.config dev",3     "build": "rimraf dist && webpack -p --env.config prod" //rimraf清空dist目录

local 명령의 경우 다음을 실행합니다. dev 명령. 하지만 마지막에는 구성인 --config=local이 있으므로 process.env.npm_config_config, <code>dev 명령의 경우 --env XXX의 경우 option.config= 'dev 값을 얻을 수 있습니다. ' 및 option.dev= true 함수에서 특히 편리합니다! 이러한 방식으로 매개변수를 동기화하여 다양한 구성 파일을 로드할 수 있습니다. -d-p에 대해 확실하지 않은 경우 여기에서 확인할 수 있습니다. 매우 상세합니다! local命令,我们执行的是dev命令,但是在最后面会--config=local,这是配置,这样我们可以通过process.env.npm_config_config获取到,而对于dev命令,对于--env XXX,我们便可以在function获取option.config= 'dev' 和 option.dev= true的值,特别方便!以此便可以同步参数来加载不同的配置文件了。对于-d-p不清楚的话,可以这里查看,很详细!

1     // 配置文件,根据 run script不同的config参数来调用不同config2     const config = require('./config/' + (process.env.npm_config_config || options.config || 'dev'))

2. modules放置模板文件、入口文件、对应模块的vue文件

将入口文件和模板文件放到modules目录(名字保持一致),webpack文件会通过glob读取modules目录,遍历生成入口文件对象和模板文件数组,如下:

 1     const entries = glob.sync('./src/modules/*.js') 2     
 const entryJsList = {} 3     const entryHtmlList = [] 4     
 for (const path of entries) { 5         const chunkName = path.slice('./src/modules/'.length, -'.js'.length) 6         
 entryJsList[chunkName] = path 7         entryHtmlList.push(new HtmlWebpackPlugin({ 8             
 template: path.replace('.js', '.html'), 9             filename: 'modules/' + chunkName + '.html',10             
 chunks: ['manifest', 'vendor', chunkName]11         }))12     }

对于HtmlWebpackPlugin插件中几个配置项的意思是,template:模板路径,filename:文件名称,这里为了区分开来模板文件我是放置在dist/modules文件夹中,而对应的编译打包好的js、img(对于图片我们是使用file-loader、url-loader进行抽离,对于这两个不是很理解的,可以看这里)、css我也是会放在dist/下对应目录的,这样目录会比较清晰。chunks:指定插入文件中的chunk,后面我们会生成manifest文件、公共vendor、以及对应生成的jscss(名称一样)

3. 处理开发环境和生产环境ExtractTextPlugin的使用情况

开发环境,不需要把css进行抽离,要以style插入html文件中,可以很好实现热替换 生产环境,需要把css进行抽离合并,如下(根据options.dev区分开发和生产):

 1     // 处理开发环境和生产环境ExtractTextPlugin的使用情况 2    
  function cssLoaders(loader, opt) { 3         const loaders = loader.split('!') 4         
  const opts = opt || {} 5         if (options.dev) { 6             if (opts.extract) { 7                 
  return loader 8             } else { 9                 return loaders10             }11         }
  else {12             const fallbackLoader = loaders.shift()13             
  return ExtractTextPlugin.extract({14                 use: loaders,15                 
  fallback: fallbackLoader16             })17         }18     }19     ...20     // 使用情况21    
   // 注意:需要安装vue-template-compiler,不然编译会报错22     {23         test: /\.vue$/,24         
   loader: 'vue-loader',25         options: {26             loaders: {27                 
   sass: cssLoaders('vue-style-loader!css-loader!sass-loader', { extract: true })28             }         
   }30     },31     ...32     {33         test: /\.(scss|sass)$/,34       
   use: cssLoaders('style-loader!css-loader!sass-loader')35     }

再使用ExtractTextPlugin合并抽离到static/css/目录

4. 定义全局常量

cli命令行(webpack -p)使用process.env.NODE_ENV不如期望效果,使用不了,所以需要使用DefinePlugin插件定义,定义形式'"development"'或JSON.stringify(process.env.NODE_ENV),我使用这样的写法'development',结果报错(针对webpack2),查找了一下网上资料,它是这样讲的,可以去看一下,设置如下:

1     new webpack.DefinePlugin({2         'process.env': {3            
 NODE_ENV: options.dev ? JSON.stringify('development') : JSON.stringify('production')4         
 }5    
 })

5. 使用eslint修正代码规范

通过eslint来检查代码的规范性,通过定义一套配置项,来规范代码,这样多人协作,写出来的代码也会比较优雅,不好的地方是,就是配置项太多,有些默认项设置我们不需要,但是确是处处限制我们,需要通过配置屏蔽掉,可以通过.eslintrc 文件或是package.json的eslintConfig

 1     ... 2   "eslintConfig": { 3     "parser": "babel-eslint", 4     "extends": "enough", 5    
  "env": { 6       "browser": true, 7       "node": true, 8       "commonjs": true, 9       "es6": true10     },
  11     "rules": {12       "linebreak-style": 0,13       "indent": [2, 4],14       "no-unused-vars": 0,15      
   "no-console": 016     },17     "plugins": [18       "html"19     ]20   },21   ...
2. 모듈은 해당 모듈의 템플릿 파일, 항목 파일 및 vue 파일을 배치합니다.🎜🎜항목 파일과 템플릿 파일을 모듈 디렉토리에 배치합니다(이름이 일치해야 함). webpack 파일은 모듈 디렉토리를 읽습니다. glob을 통해 생성된 항목 파일 객체와 템플릿 파일 배열은 다음과 같습니다. 🎜🎜
1     {2         enforce: 'pre',3         test: /.vue$/,4         loader: 'eslint-loader',5       
  exclude: /node_modules/6     }
🎜🎜HtmlWebpackPlugin 플러그인의 여러 구성 항목의 경우 템플릿: 템플릿 경로, 파일 이름: 파일 이름을 구별합니다. 여기에 템플릿 파일을 넣어 dist/modules 폴더에 넣고 해당 컴파일 및 패키지된 js, img(이미지의 경우 파일 로더, url-로더를 사용하여 추출합니다. 이 두 가지를 잘 이해하지 못합니다. 여기를 읽어보세요), CSS도 알고 있습니다. dist/ 아래의 해당 디렉터리에 배치하면 디렉터리가 더 명확해집니다. 청크: 파일에 삽입된 청크를 지정합니다. 나중에 매니페스트 파일, 공개 공급업체 및 해당 생성된 jscss(동일한 이름으로)를 생성합니다. 🎜🎜3. 개발 환경 및 프로덕션 환경에서 ExtractTextPlugin 사용을 처리합니다. 개발 환경에서는 CSS를 추출하여 스타일이 포함된 html 파일에 삽입해야 하며, 이는 핫 교체를 달성할 수 있습니다. 프로덕션 환경에서는 다음과 같이 CSS를 추출하고 병합해야 합니다(개발 환경을 구별). 그리고 options.dev에 따라 제작): 🎜🎜
1   module: {2     preLoaders: [3       {4         test: /\.js$/,5        
 loader: "eslint-loader"6       
}7     ]8   }
🎜🎜 그런 다음 ExtractTextPlugin Merge를 사용하여 static/css/ 디렉터리로 추출합니다. 🎜🎜4 전역 상수 정의 🎜🎜cli 명령줄( webpack -p) process.env.NODE_ENV를 사용하면 원하는 효과가 없으므로 사용할 수 없으므로 DefinePlugin 플러그인 정의를 사용해야 합니다. 정의 형식은 '"development"' 또는 JSON입니다. stringify(process.env.NODE_ENV) 이렇게 작성 방법을 사용했는데 결과는 오류였습니다(webpack2의 경우). 온라인 정보를 검색해 보면 이렇습니다. 🎜🎜
1     ...2     alias: {3        
 vue: 'vue/dist/vue'4     },
 5     ...
🎜🎜5. eslint를 사용하여 코드 사양을 수정합니다🎜🎜 eslint를 사용하여 코드의 표준화를 확인하고, 다음과 같이 구성 항목 집합을 정의하여 코드를 표준화합니다. 작성된 코드가 더 우아해집니다. 단점은 구성 항목이 너무 많다는 것입니다. 일부 기본 항목을 설정할 필요는 없지만 모든 곳에서 우리를 제한하고 구성을 통해 차단해야 합니다. .eslintrc 파일 또는 package.json의 eslintConfig. 다른 방법도 있습니다. 여기서는 다음과 같이 package.json 메서드를 사용합니다. 🎜

我们还需要安装 npm install eslint eslint-config-enough eslint-loader --save-dev,eslint-config-enough是所谓的配置文件,这样package.json的内容才能起效,但是不当当是这样,对应编辑器也需要安装对应的插件,sublime text 3需要安装SublimeLinter、SublimeLinter-contrib-eslint插件。对于所有规则的详解,可以去看官网,也可以去这里看,很详细!
由于我们使用的是vue-loader,自然我们是希望能对.vue文件eslint,那么需要安装eslint-plugin-html,在package.json中进行配置。然后对应webpack配置:

1     {2         enforce: 'pre',3         test: /.vue$/,4         loader: 'eslint-loader',5       
  exclude: /node_modules/6     }

我们会发现webpack v1和v2之间会有一些不同,比如webpack1对于预先加载器处理的执行是这样的,

1   module: {2     preLoaders: [3       {4         test: /\.js$/,5        
 loader: "eslint-loader"6       
}7     ]8   }

更多的不同可以到中文网看,很详细,不做拓展。

6. alias vue指向问题

1     ...2     alias: {3        
 vue: 'vue/dist/vue'4     },
 5     ...

Vue 最早会打包生成三个文件,一个是 runtime only 的文件 vue.common.js,一个是 compiler only 的文件 compiler.js,一个是 runtime + compiler 的文件 vue.js。vue.js = vue.common.js + compiler.js,默认package.json的main是指向vue.common.js,而template 属性的使用一定要用compiler.js,因此需要在alias改变vue指向

7. devServer的使用

之前的项目中使用的是用express启动http服务,webpack-dev-middleware+webpack-hot-middleware,这里会用到compiler+compilation,这个是webpack的编译器和编译过程的一些知识,也不是很懂,后续要去做做功课,应该可以加深对webpack运行机制的理解。这样做的话,感觉复杂很多,对于webpack2.0 devServer似乎功能更强大更加完善了,所以直接使用就可以了。如下:

 1     devServer: { 2         port: 8080, //端口号 3        
  proxy: { //方向代理 /api/auth/ => http://api.example.dev 4             '/api/auth/': { 5                 
  target: 'http://api.example.dev', 6                 changeOrigin: true, 7                 
  pathRewrite: { '^/api': '' } 8             } 9         },10         
  publicPath: config.publicPath,11         stats: { colors: true }12     }13     
  //changeOrigin会修改HTTP请求头中的Host为target的域名, 这里会被改为api.example.dev14     
  //pathRewrite用来改写URL, 这里我们把/api前缀去掉,直接使用/auth/请求

webpack 2 打包实战讲解得非常好,非常棒。可以去看一下,一定会有所收获!

8. 热重载原理

webpack中文网,讲的还算清楚,不过可能太笨,看起来还是云里雾里的,似懂非懂的,补补课,好好看看。

9. localtunnel的使用

Localtunnel 是一个可以让内网服务器暴露到公网上的开源项目,使用可以看这里,

1 $ npm install -g localtunnel2 $ lt --port 80803 your url is: https://uhhzexcifv.localtunnel.me

这样的话,可以把我们的本地网站暂时性地暴露到公网,可以对网站做一些线上线下对比,详细内容可以去了解一下localtunnel,这里讲的是通过上面配置,访问https://uhhzexcifv.localtunnel.me,没有达到理想效果,出现了Invalid Host header的错误,因为devServer缺少一个配置disableHostCheck: true,这样的一个配置,很多文档上面都没有说明,字面上面的意思不要去检查Host,这样设置,便可以绕过这一层检验,设置的配置项在optionsSchema.json中,issue可以看这里

文章内容可能会更新,可以关注github

위 내용은 Vue 프로젝트 스캐폴딩 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.