11 | 12 | 13 |
14 | 15 |
16 | 17 |18 | 19 |
20 |├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .vscode └── settings.json ├── README ├── README.md ├── build ├── build.js ├── dev-client.js ├── dev-server.js ├── utils.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── config ├── dev.env.js ├── index.js ├── prod.env.js └── test.env.js ├── gulpfile.js ├── index.html ├── package.json ├── src ├── assets │ ├── css │ │ ├── common.css │ │ └── m.css │ ├── images │ │ └── wechat.png │ └── util.js ├── components │ └── Modal.vue ├── config.js ├── filters │ ├── dateFormatter.js │ └── index.js ├── m │ └── login │ │ ├── app.vue │ │ ├── login.css │ │ ├── login.html │ │ └── login.js ├── module │ └── login │ │ ├── app.vue │ │ ├── login.css │ │ ├── login.html │ │ └── login.js └── services │ ├── service.js │ └── xhr │ ├── config.js │ ├── index.js │ └── vueResource.js └── static └── .gitkeep /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"], 4 | "comments": false 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module' 6 | }, 7 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 8 | extends: 'standard', 9 | // required to lint *.vue files 10 | plugins: [ 11 | 'html' 12 | ], 13 | // add your custom rules here 14 | 'rules': { 15 | // allow paren-less arrow functions 16 | 'arrow-parens': 0, 17 | // allow async-await 18 | 'generator-star-spacing': 0, 19 | // allow debugger during development 20 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | test/unit/coverage 6 | 7 | .idea/.name 8 | .idea/compiler.xml 9 | .idea/copyright/profiles_settings.xml 10 | .idea/encodings.xml 11 | .idea/merchant-web.iml 12 | .idea/misc.xml 13 | .idea/modules.xml 14 | .idea/vcs.xml 15 | .idea/workspace.xml 16 | .idea/inspectionProfiles/profiles_settings.xml 17 | .idea/inspectionProfiles/Project_Default.xml 18 | .idea/jsLibraryMappings.xml 19 | .idea/jsLinters/jshint.xml 20 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "vsicons.presets.angular": false 3 | } -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dawnyu/vue-cli-multipage/fd279916e977537e33f48ba517e3b6636d254f27/README -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ----- 2 | 基于vue-cli单页应用改成多页应用 3 | ----- 4 | #### git地址 5 | `https://github.com/dawnyu/vue-cli-multipage.git` 6 | ### 前言 7 | 从接触vue开始用的是vue-cli直接搭建单页应用,参考配合着vue-router开发起来简直爽到吊炸天,但是由于项目越来越复杂了,单页用起来可能有点力不从心,能不能弄成多页面呢,查了相关资料得到的结论是完全可以的,能多页面多入口,并且可以使用组件,还引入jQuery,这简直完美了,这个demo是从我已经改造完成的项目中摘出来的,现在演示下怎么把基于vue2的vue-cli单页模板改造成多页面,并且多入口的项目。 8 | ### 技术栈 9 | * **vue: 2.0.1** 10 | * **vue-resource:1.0.3** 11 | * **vue-router:2.0.0** 12 | * **webpack:1.13.2** 13 | * **gulp:3.9.1** 14 | * **ES6** 15 | 16 | ### 运行 17 | ``` 18 | git clone https://github.com/dawnyu/vue-cli-multipage.git 19 | npm install 20 | npm run build 21 | npm run dev 22 | ``` 23 | 24 | ### 改造后的目录 25 |  26 | 可以多目录生成目标文件 27 | 28 | 公共的js和样式图标放到assets文件夹即可 29 | 30 | ### 修改点 31 | 32 | **build/utils.js** 33 | ```js 34 | var path = require('path') 35 | var config = require('../config') 36 | var glob = require('glob') 37 | // 将样式提取到单独的css文件中,而不是打包到js文件或使用style标签插入在head标签中 38 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 39 | 40 | exports.assetsPath = function(_path) { 41 | var assetsSubDirectory = process.env.NODE_ENV === 'production' ? 42 | config.build.assetsSubDirectory : 43 | config.dev.assetsSubDirectory 44 | return path.posix.join(assetsSubDirectory, _path) 45 | } 46 | 47 | exports.cssLoaders = function(options) { 48 | options = options || {} 49 | // generate loader string to be used with extract text plugin 50 | function generateLoaders(loaders) { 51 | var sourceLoader = loaders.map(function(loader) { 52 | var extraParamChar 53 | if (/\?/.test(loader)) { 54 | loader = loader.replace(/\?/, '-loader?') 55 | extraParamChar = '&' 56 | } else { 57 | loader = loader + '-loader' 58 | extraParamChar = '?' 59 | } 60 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 61 | }).join('!') 62 | 63 | if (options.extract) { 64 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 65 | } else { 66 | return ['vue-style-loader', sourceLoader].join('!') 67 | } 68 | } 69 | 70 | // http://vuejs.github.io/vue-loader/configurations/extract-css.html 71 | return { 72 | css: generateLoaders(['css']), 73 | postcss: generateLoaders(['css']), 74 | less: generateLoaders(['css', 'less']), 75 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 76 | scss: generateLoaders(['css', 'sass']), 77 | stylus: generateLoaders(['css', 'stylus']), 78 | styl: generateLoaders(['css', 'stylus']) 79 | } 80 | } 81 | 82 | // Generate loaders for standalone style files (outside of .vue) 83 | exports.styleLoaders = function(options) { 84 | var output = [] 85 | var loaders = exports.cssLoaders(options) 86 | for (var extension in loaders) { 87 | var loader = loaders[extension] 88 | output.push({ 89 | test: new RegExp('\\.' + extension + '$'), 90 | loader: loader 91 | }) 92 | } 93 | return output 94 | } 95 | //增加获取多入口的方法 注意 这个参数是个数组 96 | exports.getEntry = function(globPaths) { 97 | var entries = {}, 98 | basename, tmp, pathname; 99 | for (globPath of globPaths) { 100 | glob.sync(globPath).forEach(function(entry) { 101 | basename = path.basename(entry, path.extname(entry)); 102 | tmp = entry.split('/').splice(-3); 103 | pathname = tmp.splice(0, 1) + '/' + basename; // 正确输出js和html的路径 104 | entries[pathname] = entry; 105 | }); 106 | } 107 | console.log(entries); 108 | return entries; 109 | } 110 | ``` 111 | **webpack.base.conf.js** 112 | ```js 113 | var path = require('path') 114 | var config = require('../config') 115 | var webpack = require('webpack') 116 | var merge = require('webpack-merge') 117 | var utils = require('./utils') 118 | var projectRoot = path.resolve(__dirname, '../') ///——driname当前目录 119 | var chunks = Object.keys(utils.getEntry(['./src/module/**/*.js', './src/m/**/*.js'])); 120 | // 将样式提取到单独的css文件中,而不是打包到js文件或使用style标签插入在head标签中 121 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 122 | module.exports = { 123 | entry: utils.getEntry(['./src/module/**/*.js', './src/m/**/*.js']),//传入需要打包的入口,我这里是pc端和手机端入口打到一个包里 124 | output: { 125 | path: config.build.assetsRoot, 126 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, //根名称可配置 127 | filename: '[name].js' 128 | }, 129 | resolve: { 130 | extensions: ['', '.js', '.vue'], 131 | fallback: [path.join(__dirname, '../node_modules')], 132 | alias: { 133 | 'src': path.resolve(__dirname, '../src'), 134 | 'assets': path.resolve(__dirname, '../src/assets'), 135 | 'components': path.resolve(__dirname, '../src/components'), 136 | 'jquery': 'jquery' 137 | } 138 | }, 139 | resolveLoader: { 140 | fallback: [path.join(__dirname, '../node_modules')] 141 | }, 142 | module: { 143 | loaders: [{ 144 | test: /\.vue$/, 145 | loader: 'vue-loader' 146 | }, 147 | { 148 | test: /\.js$/, 149 | loader: 'babel', 150 | include: projectRoot, 151 | exclude: /node_modules/ 152 | }, 153 | { 154 | test: /\.json$/, 155 | loader: 'json' 156 | }, 157 | { 158 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 159 | loader: 'url', 160 | query: { 161 | limit: 30000, 162 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 163 | } 164 | }, 165 | { 166 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 167 | loader: 'url', 168 | query: { 169 | limit: 10000, 170 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 171 | } 172 | } 173 | ] 174 | }, 175 | eslint: { 176 | formatter: require('eslint-friendly-formatter') 177 | }, 178 | vue: { 179 | loaders: utils.cssLoaders(), 180 | postcss: [ 181 | require('autoprefixer')({ 182 | browsers: ['last 2 versions'] 183 | }) 184 | ] 185 | }, 186 | plugins: [ 187 | // new webpack.optimize.CommonsChunkPlugin('static/build.js'), 188 | // 提取公共模块 189 | new webpack.optimize.CommonsChunkPlugin({ 190 | name: 'vendors', // 公共模块的名称 191 | chunks: chunks, // chunks是需要提取的模块 192 | minChunks: chunks.length 193 | }), 194 | // 配置提取出的样式文件 195 | new ExtractTextPlugin('css/[name].css'), 196 | //引入jqury 197 | new webpack.ProvidePlugin({ 198 | $: "jquery", 199 | jQuery: "jquery" 200 | }) 201 | ], 202 | } 203 | ``` 204 | 205 | **webpack.dev.conf.js** 206 | ```js 207 | var config = require('../config') 208 | var webpack = require('webpack') 209 | var merge = require('webpack-merge') 210 | var utils = require('./utils') 211 | var baseWebpackConfig = require('./webpack.base.conf') 212 | var HtmlWebpackPlugin = require('html-webpack-plugin') 213 | // add hot-reload related code to entry chunks 214 | Object.keys(baseWebpackConfig.entry).forEach(function(name) { 215 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 216 | }) 217 | 218 | module.exports = merge(baseWebpackConfig, { 219 | module: { 220 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 221 | }, 222 | // eval-source-map is faster for development 223 | devtool: '#eval-source-map', 224 | plugins: [ 225 | new webpack.DefinePlugin({ 226 | 'process.env': config.dev.env 227 | }), 228 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 229 | new webpack.optimize.OccurenceOrderPlugin(), 230 | new webpack.HotModuleReplacementPlugin(), 231 | new webpack.NoErrorsPlugin(), 232 | // https://github.com/ampedandwired/html-webpack-plugin 233 | // new HtmlWebpackPlugin({ 234 | // filename: 'index.html', 235 | // template: 'index.html', 236 | // inject: true 237 | // }) 238 | ] 239 | }) 240 | 241 | var pages = utils.getEntry(['./src/module/**/*.html', './src/m/**/*.html']); 242 | 243 | 244 | for (var pathname in pages) { 245 | 246 | 247 | // 配置生成的html文件,定义路径等 248 | var conf = { 249 | filename: pathname + '.html', 250 | template: pages[pathname], // 模板路径 251 | favicon: './src/assets/images/wechat.png', 252 | inject: true // js插入位置 253 | 254 | }; 255 | 256 | 257 | if (pathname in module.exports.entry) { 258 | conf.chunks = ['vendors', pathname]; 259 | conf.hash = true; 260 | } 261 | 262 | module.exports.plugins.push(new HtmlWebpackPlugin(conf)); 263 | } 264 | ``` 265 | 266 | **webpack.prod.conf.js** 267 | ```js 268 | var path = require('path') 269 | var config = require('../config') 270 | var utils = require('./utils') 271 | var webpack = require('webpack') 272 | var merge = require('webpack-merge') 273 | var baseWebpackConfig = require('./webpack.base.conf') 274 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 275 | var HtmlWebpackPlugin = require('html-webpack-plugin') 276 | var env = process.env.NODE_ENV === 'testing' ? 277 | require('../config/test.env') : 278 | config.build.env 279 | 280 | module.exports = merge(baseWebpackConfig, { 281 | module: { 282 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) 283 | }, 284 | devtool: config.build.productionSourceMap ? '#source-map' : false, 285 | output: { 286 | path: config.build.assetsRoot, 287 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 288 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 289 | }, 290 | vue: { 291 | loaders: utils.cssLoaders({ 292 | sourceMap: config.build.productionSourceMap, 293 | extract: true 294 | }) 295 | }, 296 | plugins: [ 297 | // http://vuejs.github.io/vue-loader/workflow/production.html 298 | new webpack.DefinePlugin({ 299 | 'process.env': env 300 | }), 301 | new webpack.optimize.UglifyJsPlugin({ 302 | compress: { 303 | warnings: false, 304 | drop_debugger: true, 305 | drop_console: true 306 | } 307 | }), 308 | new webpack.optimize.OccurenceOrderPlugin(), 309 | // extract css into its own file 310 | new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), 311 | // generate dist index.html with correct asset hash for caching. 312 | // you can customize output by editing /index.html 313 | // see https://github.com/ampedandwired/html-webpack-plugin 314 | // new HtmlWebpackPlugin({ 315 | // filename: process.env.NODE_ENV === 'testing' ? 316 | // 'index.html' : config.build.index, 317 | // template: 'index.html', 318 | // favicon: './src/assets/images/tjd.ico', 319 | // inject: true, 320 | // minify: { 321 | // removeComments: true, 322 | // collapseWhitespace: true, 323 | // removeAttributeQuotes: true 324 | // // more options: 325 | // // https://github.com/kangax/html-minifier#options-quick-reference 326 | // }, 327 | // // necessary to consistently work with multiple chunks via CommonsChunkPlugin 328 | // chunksSortMode: 'dependency' 329 | // }), 330 | // split vendor js into its own file 331 | new webpack.optimize.CommonsChunkPlugin({ 332 | name: 'vendor', 333 | minChunks: function(module, count) { 334 | // any required modules inside node_modules are extracted to vendor 335 | return ( 336 | module.resource && 337 | /\.js$/.test(module.resource) && 338 | module.resource.indexOf( 339 | path.join(__dirname, '../node_modules') 340 | ) === 0 341 | ) 342 | } 343 | }), 344 | // extract webpack runtime and module manifest to its own file in order to 345 | // prevent vendor hash from being updated whenever app bundle is updated 346 | new webpack.optimize.CommonsChunkPlugin({ 347 | name: 'manifest', 348 | chunks: ['vendor'] 349 | }) 350 | ] 351 | }) 352 | 353 | if (config.build.productionGzip) { 354 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 355 | 356 | webpackConfig.plugins.push( 357 | new CompressionWebpackPlugin({ 358 | asset: '[path].gz[query]', 359 | algorithm: 'gzip', 360 | test: new RegExp( 361 | '\\.(' + 362 | config.build.productionGzipExtensions.join('|') + 363 | ')$' 364 | ), 365 | threshold: 10240, 366 | minRatio: 0.8 367 | }) 368 | ) 369 | } 370 | 371 | var pages = utils.getEntry(['./src/module/**/*.html', './src/m/**/*.html']); 372 | 373 | for (var pathname in pages) { 374 | 375 | 376 | // 配置生成的html文件,定义路径等 377 | var conf = { 378 | filename: pathname + '.html', 379 | template: pages[pathname], // 模板路径 380 | favicon: './src/assets/images/wechat.png', 381 | inject: true // js插入位置 382 | 383 | }; 384 | if (pathname in pages) { 385 | conf.chunks = ['vendors', pathname]; 386 | conf.hash = true; 387 | } 388 | 389 | module.exports.plugins.push(new HtmlWebpackPlugin(conf)); 390 | } 391 | ``` 392 | 393 | #### 具体怎么使用当可以查看下代码中使用 394 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | // https://github.com/shelljs/shelljs 2 | //打包文件 命令 npm run build 3 | require('shelljs/global') 4 | env.NODE_ENV = 'production' 5 | 6 | var path = require('path') 7 | var config = require('../config') 8 | var ora = require('ora') //Elegant terminal spinner 终端 9 | var webpack = require('webpack') 10 | var webpackConfig = require('./webpack.prod.conf') 11 | 12 | console.log( 13 | ' Tip:\n' + 14 | ' Built files are meant to be served over an HTTP server.\n' + 15 | ' Opening index.html over file:// won\'t work.\n' 16 | ) 17 | 18 | var spinner = ora('building for production...') 19 | spinner.start() 20 | 21 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) 22 | rm('-rf', assetsPath) 23 | mkdir('-p', assetsPath) 24 | cp('-R', 'static/*', assetsPath) 25 | 26 | webpack(webpackConfig, function (err, stats) { 27 | spinner.stop() 28 | if (err) throw err 29 | process.stdout.write(stats.toString({ 30 | colors: true, 31 | modules: false, 32 | children: false, 33 | chunks: false, 34 | chunkModules: false 35 | }) + '\n') 36 | }) 37 | -------------------------------------------------------------------------------- /build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /build/dev-server.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var express = require('express') 3 | var webpack = require('webpack') 4 | var config = require('../config') 5 | var opn = require('opn') 6 | var proxyMiddleware = require('http-proxy-middleware') 7 | var webpackConfig = process.env.NODE_ENV === 'testing' 8 | ? require('./webpack.prod.conf') 9 | : require('./webpack.dev.conf') 10 | 11 | // default port where dev server listens for incoming traffic 12 | var port = process.env.PORT || config.dev.port 13 | // Define HTTP proxies to your custom API backend 14 | // https://github.com/chimurai/http-proxy-middleware 15 | var proxyTable = config.dev.proxyTable 16 | 17 | var app = express() 18 | var compiler = webpack(webpackConfig) 19 | 20 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 21 | publicPath: webpackConfig.output.publicPath, 22 | stats: { 23 | colors: true, 24 | chunks: false 25 | } 26 | }) 27 | 28 | var hotMiddleware = require('webpack-hot-middleware')(compiler) 29 | // force page reload when html-webpack-plugin template changes 30 | compiler.plugin('compilation', function (compilation) { 31 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 32 | hotMiddleware.publish({ action: 'reload' }) 33 | cb() 34 | }) 35 | }) 36 | 37 | // proxy api requests 38 | Object.keys(proxyTable).forEach(function (context) { 39 | var options = proxyTable[context] 40 | if (typeof options === 'string') { 41 | options = { target: options } 42 | } 43 | app.use(proxyMiddleware(context, options)) 44 | }) 45 | 46 | // handle fallback for HTML5 history API 47 | app.use(require('connect-history-api-fallback')()) 48 | 49 | // serve webpack bundle output 50 | app.use(devMiddleware) 51 | 52 | // enable hot-reload and state-preserving 53 | // compilation error display 54 | app.use(hotMiddleware) 55 | 56 | // serve pure static assets 57 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 58 | app.use(staticPath, express.static('./static')) 59 | 60 | module.exports = app.listen(port, function (err) { 61 | if (err) { 62 | console.log(err) 63 | return 64 | } 65 | var uri = 'http://localhost:' + port 66 | console.log('Listening at ' + uri + '\n') 67 | opn(uri) 68 | }) 69 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var glob = require('glob') 4 | // 将样式提取到单独的css文件中,而不是打包到js文件或使用style标签插入在head标签中 5 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 6 | 7 | exports.assetsPath = function(_path) { 8 | var assetsSubDirectory = process.env.NODE_ENV === 'production' ? 9 | config.build.assetsSubDirectory : 10 | config.dev.assetsSubDirectory 11 | return path.posix.join(assetsSubDirectory, _path) 12 | } 13 | 14 | exports.cssLoaders = function(options) { 15 | options = options || {} 16 | // generate loader string to be used with extract text plugin 17 | function generateLoaders(loaders) { 18 | var sourceLoader = loaders.map(function(loader) { 19 | var extraParamChar 20 | if (/\?/.test(loader)) { 21 | loader = loader.replace(/\?/, '-loader?') 22 | extraParamChar = '&' 23 | } else { 24 | loader = loader + '-loader' 25 | extraParamChar = '?' 26 | } 27 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 28 | }).join('!') 29 | 30 | if (options.extract) { 31 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 32 | } else { 33 | return ['vue-style-loader', sourceLoader].join('!') 34 | } 35 | } 36 | 37 | // http://vuejs.github.io/vue-loader/configurations/extract-css.html 38 | return { 39 | css: generateLoaders(['css']), 40 | postcss: generateLoaders(['css']), 41 | less: generateLoaders(['css', 'less']), 42 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 43 | scss: generateLoaders(['css', 'sass']), 44 | stylus: generateLoaders(['css', 'stylus']), 45 | styl: generateLoaders(['css', 'stylus']) 46 | } 47 | } 48 | 49 | // Generate loaders for standalone style files (outside of .vue) 50 | exports.styleLoaders = function(options) { 51 | var output = [] 52 | var loaders = exports.cssLoaders(options) 53 | for (var extension in loaders) { 54 | var loader = loaders[extension] 55 | output.push({ 56 | test: new RegExp('\\.' + extension + '$'), 57 | loader: loader 58 | }) 59 | } 60 | return output 61 | } 62 | 63 | exports.getEntry = function(globPaths) { 64 | var entries = {}, 65 | basename, tmp, pathname; 66 | for (globPath of globPaths) { 67 | glob.sync(globPath).forEach(function(entry) { 68 | basename = path.basename(entry, path.extname(entry)); 69 | tmp = entry.split('/').splice(-3); 70 | pathname = tmp.splice(0, 1) + '/' + basename; // 正确输出js和html的路径 71 | entries[pathname] = entry; 72 | }); 73 | } 74 | console.log(entries); 75 | return entries; 76 | } -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var webpack = require('webpack') 4 | var merge = require('webpack-merge') 5 | var utils = require('./utils') 6 | var projectRoot = path.resolve(__dirname, '../') ///——driname当前目录 7 | var chunks = Object.keys(utils.getEntry(['./src/module/**/*.js', './src/m/**/*.js'])); 8 | // 将样式提取到单独的css文件中,而不是打包到js文件或使用style标签插入在head标签中 9 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 10 | module.exports = { 11 | entry: utils.getEntry(['./src/module/**/*.js', './src/m/**/*.js']), 12 | output: { 13 | path: config.build.assetsRoot, 14 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, //根名称可配置 15 | filename: '[name].js' 16 | }, 17 | resolve: { 18 | extensions: ['', '.js', '.vue'], 19 | fallback: [path.join(__dirname, '../node_modules')], 20 | alias: { 21 | 'src': path.resolve(__dirname, '../src'), 22 | 'assets': path.resolve(__dirname, '../src/assets'), 23 | 'components': path.resolve(__dirname, '../src/components'), 24 | 'jquery': 'jquery' 25 | } 26 | }, 27 | resolveLoader: { 28 | fallback: [path.join(__dirname, '../node_modules')] 29 | }, 30 | module: { 31 | loaders: [{ 32 | test: /\.vue$/, 33 | loader: 'vue-loader' 34 | }, 35 | { 36 | test: /\.js$/, 37 | loader: 'babel', 38 | include: projectRoot, 39 | exclude: /node_modules/ 40 | }, 41 | { 42 | test: /\.json$/, 43 | loader: 'json' 44 | }, 45 | { 46 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 47 | loader: 'url', 48 | query: { 49 | limit: 30000, 50 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 51 | } 52 | }, 53 | { 54 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 55 | loader: 'url', 56 | query: { 57 | limit: 10000, 58 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 59 | } 60 | } 61 | ] 62 | }, 63 | eslint: { 64 | formatter: require('eslint-friendly-formatter') 65 | }, 66 | vue: { 67 | loaders: utils.cssLoaders(), 68 | postcss: [ 69 | require('autoprefixer')({ 70 | browsers: ['last 2 versions'] 71 | }) 72 | ] 73 | }, 74 | plugins: [ 75 | // new webpack.optimize.CommonsChunkPlugin('static/build.js'), 76 | // 提取公共模块 77 | new webpack.optimize.CommonsChunkPlugin({ 78 | name: 'vendors', // 公共模块的名称 79 | chunks: chunks, // chunks是需要提取的模块 80 | minChunks: chunks.length 81 | }), 82 | // 配置提取出的样式文件 83 | new ExtractTextPlugin('css/[name].css'), 84 | new webpack.ProvidePlugin({ 85 | $: "jquery", 86 | jQuery: "jquery" 87 | }) 88 | ], 89 | } -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var config = require('../config') 2 | var webpack = require('webpack') 3 | var merge = require('webpack-merge') 4 | var utils = require('./utils') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | // add hot-reload related code to entry chunks 8 | Object.keys(baseWebpackConfig.entry).forEach(function(name) { 9 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 10 | }) 11 | 12 | module.exports = merge(baseWebpackConfig, { 13 | module: { 14 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 15 | }, 16 | // eval-source-map is faster for development 17 | devtool: '#eval-source-map', 18 | plugins: [ 19 | new webpack.DefinePlugin({ 20 | 'process.env': config.dev.env 21 | }), 22 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 23 | new webpack.optimize.OccurenceOrderPlugin(), 24 | new webpack.HotModuleReplacementPlugin(), 25 | new webpack.NoErrorsPlugin(), 26 | // https://github.com/ampedandwired/html-webpack-plugin 27 | // new HtmlWebpackPlugin({ 28 | // filename: 'index.html', 29 | // template: 'index.html', 30 | // inject: true 31 | // }) 32 | ] 33 | }) 34 | 35 | var pages = utils.getEntry(['./src/module/**/*.html', './src/m/**/*.html']); 36 | 37 | 38 | for (var pathname in pages) { 39 | 40 | 41 | // 配置生成的html文件,定义路径等 42 | var conf = { 43 | filename: pathname + '.html', 44 | template: pages[pathname], // 模板路径 45 | favicon: './src/assets/images/wechat.png', 46 | inject: true // js插入位置 47 | 48 | }; 49 | 50 | 51 | if (pathname in module.exports.entry) { 52 | conf.chunks = ['vendors', pathname]; 53 | conf.hash = true; 54 | } 55 | 56 | module.exports.plugins.push(new HtmlWebpackPlugin(conf)); 57 | } -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var env = process.env.NODE_ENV === 'testing' ? 10 | require('../config/test.env') : 11 | config.build.env 12 | 13 | module.exports = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) 16 | }, 17 | devtool: config.build.productionSourceMap ? '#source-map' : false, 18 | output: { 19 | path: config.build.assetsRoot, 20 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 21 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 22 | }, 23 | vue: { 24 | loaders: utils.cssLoaders({ 25 | sourceMap: config.build.productionSourceMap, 26 | extract: true 27 | }) 28 | }, 29 | plugins: [ 30 | // http://vuejs.github.io/vue-loader/workflow/production.html 31 | new webpack.DefinePlugin({ 32 | 'process.env': env 33 | }), 34 | new webpack.optimize.UglifyJsPlugin({ 35 | compress: { 36 | warnings: false, 37 | drop_debugger: true, 38 | drop_console: true 39 | } 40 | }), 41 | new webpack.optimize.OccurenceOrderPlugin(), 42 | // extract css into its own file 43 | new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), 44 | // generate dist index.html with correct asset hash for caching. 45 | // you can customize output by editing /index.html 46 | // see https://github.com/ampedandwired/html-webpack-plugin 47 | // new HtmlWebpackPlugin({ 48 | // filename: process.env.NODE_ENV === 'testing' ? 49 | // 'index.html' : config.build.index, 50 | // template: 'index.html', 51 | // favicon: './src/assets/images/tjd.ico', 52 | // inject: true, 53 | // minify: { 54 | // removeComments: true, 55 | // collapseWhitespace: true, 56 | // removeAttributeQuotes: true 57 | // // more options: 58 | // // https://github.com/kangax/html-minifier#options-quick-reference 59 | // }, 60 | // // necessary to consistently work with multiple chunks via CommonsChunkPlugin 61 | // chunksSortMode: 'dependency' 62 | // }), 63 | // split vendor js into its own file 64 | new webpack.optimize.CommonsChunkPlugin({ 65 | name: 'vendor', 66 | minChunks: function(module, count) { 67 | // any required modules inside node_modules are extracted to vendor 68 | return ( 69 | module.resource && 70 | /\.js$/.test(module.resource) && 71 | module.resource.indexOf( 72 | path.join(__dirname, '../node_modules') 73 | ) === 0 74 | ) 75 | } 76 | }), 77 | // extract webpack runtime and module manifest to its own file in order to 78 | // prevent vendor hash from being updated whenever app bundle is updated 79 | new webpack.optimize.CommonsChunkPlugin({ 80 | name: 'manifest', 81 | chunks: ['vendor'] 82 | }) 83 | ] 84 | }) 85 | 86 | if (config.build.productionGzip) { 87 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 88 | 89 | webpackConfig.plugins.push( 90 | new CompressionWebpackPlugin({ 91 | asset: '[path].gz[query]', 92 | algorithm: 'gzip', 93 | test: new RegExp( 94 | '\\.(' + 95 | config.build.productionGzipExtensions.join('|') + 96 | ')$' 97 | ), 98 | threshold: 10240, 99 | minRatio: 0.8 100 | }) 101 | ) 102 | } 103 | 104 | var pages = utils.getEntry(['./src/module/**/*.html', './src/m/**/*.html']); 105 | 106 | for (var pathname in pages) { 107 | 108 | 109 | // 配置生成的html文件,定义路径等 110 | var conf = { 111 | filename: pathname + '.html', 112 | template: pages[pathname], // 模板路径 113 | favicon: './src/assets/images/wechat.png', 114 | inject: true // js插入位置 115 | 116 | }; 117 | if (pathname in pages) { 118 | conf.chunks = ['vendors', pathname]; 119 | conf.hash = true; 120 | } 121 | 122 | module.exports.plugins.push(new HtmlWebpackPlugin(conf)); 123 | } -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: '/newmerchant/', 11 | productionSourceMap: false, //是否打开打包映射文件 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'] 18 | }, 19 | dev: { 20 | env: require('./dev.env'), 21 | port: 8080, 22 | assetsSubDirectory: 'static', 23 | assetsPublicPath: '/', 24 | proxyTable: {}, 25 | // CSS Sourcemaps off by default because relative paths are "buggy" 26 | // with this option, according to the CSS-Loader README 27 | // (https://github.com/webpack/css-loader#sourcemaps) 28 | // In our experience, they generally work as expected, 29 | // just be aware of this issue when enabling this option. 30 | cssSourceMap: false 31 | } 32 | } -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /config/test.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var devEnv = require('./dev.env') 3 | 4 | module.exports = merge(devEnv, { 5 | NODE_ENV: '"testing"' 6 | }) 7 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp')//加载gulp模块 4 | var webpack = require('webpack') 5 | var Q = require('q')//Q模块。适用于把异步转成同步执行,抽空换成ES6实现 6 | var minimist = require('minimist')//传参 7 | var ora = require('ora')//终端管理 8 | var pro = require('child_process')//运行子进程库 9 | var sftp = require('gulp-sftp')//sftp上传程序 10 | var knownOptions = { 11 | string: 'env', 12 | default: {env: process.env.NODE_ENV || 'production'} 13 | }; 14 | 15 | var gutil = require('gulp-util'), 16 | options = minimist(process.argv.slice(2), knownOptions), 17 | src = process.cwd() + '/src', 18 | assets = process.cwd() + '/dist', 19 | remoteServer1 = { 20 | host: '123.56.7.118', 21 | port:22444, 22 | remotePath: '/server/nginx/html/newmerchant/newmerchant', 23 | user: 'tjd', 24 | pass: 'tjd.ser.lb1' 25 | }, 26 | remoteServer2 = { 27 | host: '123.56.8.169', 28 | port:22444, 29 | remotePath: '/server/nginx/html/newmerchant/newmerchant', 30 | user: 'tjd', 31 | pass: 'tjd.ser.lb2' 32 | } 33 | //先执行build命令打包。在把程序上传至服务器 34 | gulp.task('deploy',() => build().then(() => { 35 | gulp.src(assets + '/**').pipe(sftp(remoteServer1)) 36 | gulp.src(assets + '/**').pipe(sftp(remoteServer2)) 37 | }) 38 | ) 39 | var build = () => { 40 | var deferred = Q.defer() 41 | pro.exec('npm run build',(error, stdout, stderr) => { 42 | if (error !== null) { 43 | console.log('exec error: ' + error) 44 | } 45 | console.log('build codeing finished') 46 | deferred.resolve() 47 | }) 48 | return deferred.promise 49 | } 50 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |通知
登录
7 |11 | 12 | 13 |
14 | 15 |
16 | 17 |18 | 19 |
20 |