使用vue+webpack的多页面架构(转+自己的情况)

Posted 弱水三千,只取一瓢

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用vue+webpack的多页面架构(转+自己的情况)相关的知识,希望对你有一定的参考价值。

按以下步骤可正常配置多页面架构

记得安装 node-glob   安装命令:npm install node-glob --save-dev

文件附加

webpack.base.conf.js --参考more start  处

var path = require(\'path\')
var utils = require(\'./utils\')
var config = require(\'../config\')
var vueLoaderConfig = require(\'./vue-loader.conf\')
var webpack=require(\'webpack\'); //加入webpack对象

//more
var glob = require(\'glob\'); //node-glob
var entries = getEntry(\'./src/views/**/*.js\'); // 获得入口js文件. views替换了module
//more end
function resolve (dir) {
  return path.join(__dirname, \'..\', dir)
}
function getEntry(globPath) {
  var entries = {},
    basename, tmp, pathname;

  glob.sync(globPath).forEach(function (entry) {
    basename = path.basename(entry, path.extname(entry));
    tmp = entry.split(\'/\').splice(-3);
    pathname = tmp.splice(0, 1) + \'/\' + basename; // 正确输出js和html的路径
    entries[pathname] = entry;
  });
  console.log("base-entrys:",entries);
  return entries;
}
module.exports = {
  entry:entries ,
  // entry: {
  //   app: \'./src/main.js\'
  // },
  output: {
    path: config.build.assetsRoot,
    filename: \'[name].js\',
    publicPath: process.env.NODE_ENV === \'production\'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: [\'.js\', \'.vue\', \'.json\'],
    alias: {
      \'vue$\': \'vue/dist/vue.esm.js\',
      \'@\': resolve(\'src\'),
      \'basecommon\':\'./../../../common\',//base组件引入公共样式
      \'components\':\'./../components\',//非base组件,./../common
      \'api\':\'./../../api\',//非base组件
      \'base\':\'./../base\' //非base组件引入base组件
    }
  },
  module: {
    rules: [
      {
        test: /\\.vue$/,
        loader: \'vue-loader\',
        options: vueLoaderConfig
      },
      {
        test: /\\.js$/,
        loader: \'babel-loader\',
        include: [resolve(\'src\'), resolve(\'test\')]
      },
      {
        test: /\\.(png|jpe?g|gif|svg)(\\?.*)?$/,
        loader: \'url-loader\',
        options: {
          limit: 10000,
          name: utils.assetsPath(\'images/[name].[hash:7].[ext]\')
        }
      },
      {
        test: /\\.(woff2?|eot|ttf|otf)(\\?.*)?$/,
        loader: \'url-loader\',
        options: {
          limit: 10000,
          name: utils.assetsPath(\'fonts/[name].[hash:7].[ext]\')
        }
      }
    ]
  },
  plugins: [  
  new webpack.ProvidePlugin({  
    $:"jquery",  
    jQuery:"jquery",  
    "windows.jQuery":"jquery"  
  })  
] 
}
View Code

webpack.dev.conf.js --参考more start  处

var utils = require(\'./utils\')
var webpack = require(\'webpack\')
var config = require(\'../config\')
var merge = require(\'webpack-merge\')
var baseWebpackConfig = require(\'./webpack.base.conf\')
var HtmlWebpackPlugin = require(\'html-webpack-plugin\')
var FriendlyErrorsPlugin = require(\'friendly-errors-webpack-plugin\')

//more
var path = require(\'path\');
var glob = require(\'glob\');
//more end

// add hot-reload related code to entry chunks
Object.keys(baseWebpackConfig.entry).forEach(function (name) {
  baseWebpackConfig.entry[name] = [\'./build/dev-client\'].concat(baseWebpackConfig.entry[name])
})

function getEntry(globPath) {
  var entries = {},
    basename, tmp, pathname;

  glob.sync(globPath).forEach(function(entry) {
    basename = path.basename(entry, path.extname(entry));
    tmp = entry.split(\'/\').splice(-3);
    pathname = tmp.splice(0, 1) + \'/\' + basename; // 正确输出js和html的路径
    entries[pathname] = entry;
  });
  console.log("dev-entrys:",entries);
  return entries;
}

//more end

module.exports = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap })
  },
  // cheap-module-eval-source-map is faster for development
  devtool: \'#cheap-module-eval-source-map\',
  plugins: [
    new webpack.DefinePlugin({
      \'process.env\': config.dev.env
    }),
    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoEmitOnErrorsPlugin(),
    // https://github.com/ampedandwired/html-webpack-plugin
    // new HtmlWebpackPlugin({
    //   filename: \'index.html\',
    //   template: \'index.html\',
    //   inject: true
    // }),
    new FriendlyErrorsPlugin()
  ]
})

//more start 先定义后插入
var pages = getEntry(\'./src/views/**/*.html\');
console.log("dev pages----------------------");
for (var pathname in pages) {
  console.log("filename:" + pathname + \'.html\');
  console.log("template:" + pages[pathname]);
  // 配置生成的html文件,定义路径等
  var conf = {
    filename: pathname + \'.html\',
    template: pages[pathname], // 模板路径
    minify: { //传递 html-minifier 选项给 minify 输出
      removeComments: true
    },
    inject: \'body\', // js插入位置
    chunks: [pathname, "vendor", "manifest"] // 每个html引用的js模块,也可以在这里加上vendor等公用模块
  };
  // 需要生成几个html文件,就配置几个HtmlWebpackPlugin对象
  module.exports.plugins.push(new HtmlWebpackPlugin(conf));
}
View Code

 

webpack.prod.conf.js --参考more start  处

var path = require(\'path\')
var utils = require(\'./utils\')
var webpack = require(\'webpack\')
var config = require(\'../config\')
var merge = require(\'webpack-merge\')
var baseWebpackConfig = require(\'./webpack.base.conf\')
var CopyWebpackPlugin = require(\'copy-webpack-plugin\')
var HtmlWebpackPlugin = require(\'html-webpack-plugin\')
var ExtractTextPlugin = require(\'extract-text-webpack-plugin\')
var OptimizeCSSPlugin = require(\'optimize-css-assets-webpack-plugin\')

//more
var path = require(\'path\');
var glob = require(\'glob\');
//more end

var env = config.build.env

var webpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({
      sourceMap: config.build.productionSourceMap,
      extract: true
    })
  },
  devtool: config.build.productionSourceMap ? \'#source-map\' : false,
  output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath(\'js/[name].[chunkhash].js\'),
    chunkFilename: utils.assetsPath(\'js/[id].[chunkhash].js\')
  },
  plugins: [
    // http://vuejs.github.io/vue-loader/en/workflow/production.html
    new webpack.DefinePlugin({
      \'process.env\': env
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      },
      sourceMap: true
    }),
    // extract css into its own file
    new ExtractTextPlugin({
      filename: utils.assetsPath(\'css/[name].[contenthash].css\')
    }),
    // Compress extracted CSS. We are using this plugin so that possible
    // duplicated CSS from different components can be deduped.
    new OptimizeCSSPlugin({
      cssProcessorOptions: {
        safe: true
      }
    }),
    // generate dist index.html with correct asset hash for caching.
    // you can customize output by editing /index.html
    // see https://github.com/ampedandwired/html-webpack-plugin
/*    new HtmlWebpackPlugin({
      filename: config.build.index,
      template: \'index.html\',
      inject: true,
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference
      },
      // necessary to consistently work with multiple chunks via CommonsChunkPlugin
      chunksSortMode: \'dependency\'
    }),*/
    // split vendor js into its own file
    new webpack.optimize.CommonsChunkPlugin({
      name: \'vendor\',
      minChunks: function (module, count) {
        // any required modules inside node_modules are extracted to vendor
        return (
          module.resource &&
          /\\.js$/.test(module.resource) &&
          module.resource.indexOf(
            path.join(__dirname, \'../node_modules\')
          ) === 0
        )
      }
    }),
    // extract webpack runtime and module manifest to its own file in order to
    // prevent vendor hash from being updated whenever app bundle is updated
    new webpack.optimize.CommonsChunkPlugin({
      name: \'manifest\',
      chunks: [\'vendor\']
    }),
    // copy custom static assets
    new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, \'../static\'),
        to: config.build.assetsSubDirectory,
        ignore: [\'.*\']
      }
    ])
  ]
})

if (config.build.productionGzip) {
  var CompressionWebpackPlugin = require(\'compression-webpack-plugin\')

  webpackConfig.plugins.push(
    new CompressionWebpackPlugin({
      asset: \'[path].gz[query]\',
      algorithm: \'gzip\',
      test: new RegExp(
        \'\\\\.(\' +
        config.build.productionGzipExtensions.join(\'|\') +
        \')$\'
      ),
      threshold: 10240,
      minRatio: 0.8
    })
  )
}

if (config.build.bundleAnalyzerReport) {
  var BundleAnalyzerPlugin = require(\'webpack-bundle-analyzer\').BundleAnalyzerPlugin
  webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig


//more start
function getEntry(globPath) {
  var entries = {},
    basename, tmp, pathname;

  glob.sync(globPath).forEach(function(entry) {
    basename = path.basename(entry, path.extname(entry));
    tmp = entry.split(\'/\').splice(-3);
    pathname = tmp.splice(0, 1) + \'/\' + basename; // 正确输出js和html的路径
    entries[pathname] = entry;
  });
  console.log("pro-entrys:",entries);
  return entries;
}

var pages = getEntry(\'./src/views/**/*.html\');
console.log("pro pages----------------------");
for (var pathname in pages) {
  console.log("filename:" + pathname + \'.html\');
  console.log("template:" + pages[pathname]);
  // 配置生成的html文件,定义路径等
  var conf = {
    filename: pathname + \'.html\',
    template: pages[pathname], // 模板路径
    minify: { //传递 html-minifier 选项给 minify 输出
      removeComments: true,
      collapseWhitespace: true,
      removeAttributeQuotes: true
    },
    inject: \'body\', // js插入位置
    chunks: [pathname, "vendor", "manifest"], // 每个html引用的js模块,也可以在这里加上vendor等公用模块
     // necessary to consistently work with multiple chunks via CommonsChunkPlugin
    chunksSortMode: \'dependency\'
  };
  // 需要生成几个html文件,就配置几个HtmlWebpackPlugin对象
  module.exports.plugins.push(new HtmlWebpackPlugin(conf));
}



     
View Code

 

 

-----------------横线内为转的-----------------------

首先,要大概知道webpack是什么,webpack的插件都是做什么用的,vue是什么,然后看完之后也可以去补充一下这些方面的知识。

 

 

第一步:安装环境

 

需要安装的有:

  1. nodejs,并添加入环境变量PATH
  2. 使用nodejs安装vue-cli 
    参考内容: 
    http://cn.vuejs.org/guide/installation.html#u547D_u4EE4_u884C_u5DE5_u5177 
    使用命令: 

    npm install -g vue-cli 
  3. 使用nodejs安装webpack和webpack-dev-server 
    参考内容: 
    http://webpack.github.io/docs/tutorials/getting-started/ 
    使用命令: 

    npm install webpack -g 

    之所以要在全局安装webpack是因为使用webpack的命令行方便,不需要在每一个项目中到node_module中调用。
  4. Atom编辑器 
    这个从网上下载,https://atom.io/。这是一个开源的编辑器软件,之所以选择atom,是因为它集合了sublimeText和其他一些编辑器的优点。最大的好处是可以使用package插件的形式对atom编辑器进行自定义扩展。

第二步:创建项目模板

vue init wepack vue-multipage-demo

如上所示,这条命令的意思是使用vue的init命令,创建一个基于webpack组件化管理的项目。这将会在D:\\WS_WebStorm目录下创建新目录vue-multipage-demo。 
 
图2 
如图2,在经过设置之后,可以看到已经生成了一个项目vue-multipage-demo,接下来需要切换到项目目录下进行操作。在资源管理器中,我们可以看到已经生成了这样的目录: 
生成的文件结构 
图3 
如图3,各个文件夹和文件分别是: 
build webpack构建过程的设置文件,包括调试和发布版本以及一些工具函数 
config 这里是webpack-dev-server的一些设定,关于webpack和webpack-dev-server的设定,详见官方文档 
src 项目的源文件所在,按照你需要的样子写js和html文件,webpack将打包成浏览器可识别的,如ES6 
static 这里是存放静态资源的地方,在build之后会生成dist文件夹,这个文件夹中的文件会原封不动放进去 
.babelrc webpack插件babel的设置 
.editorconfig 这是atom编辑器生成的配置文件,在各个项目中可以自由配置 
.eslintignore 使用eslint检测代码是否符合规则的忽略目录,用于eslint设置 
.gitignore 使用Git版本管理时需要忽略的目录,用于git设置 
index.html 项目生成后的入口页面,因为vue默认是使用单页面的,所以在webpack中同时也只有这一个入口 
package.json nodejs的配置 
README.md 说明文件,其中说明了使用vue-cli创建项目之后应该怎么做 
dist build之后生成的目录,其中存放webpack打包之后的结果,webpack中需要指定build规则 
表1 
npm install 
图4 
如图4,执行这两条命令,切换到项目目录下,使用npm的安装命令,对已经生成的package.json所依赖的组件进行安装。当然,我们之后还会安装一些其他的插件。

第三步:补充需要的插件

虽然说,在项目开发中,插件的补充是根据需求进行增减的,但是在这个项目中,有一些基本的需要添加的插件,我在这里提出。package.json中的代码如下:

"dependencies": {
    "babel-runtime": "^6.0.0",
    "bootstrap": "^3.3.7",
    "bootstrap-table": "^1.11.0",
    "font-awesome": "^4.6.3",
    "jquery": "^3.1.0",
    "node-glob": "^1.2.0",
    "vue": "^1.0.21",
    "vue-resource": "^0.9.3"
  },
  "devDependencies": {
    "babel-core": "^6.0.0",
    "babel-eslint": "^6.1.2",
    "babel-loader": "^6.0.0",
    "babel-plugin-transform-runtime": "^6.0.0",
    "babel-preset-es2015": "^6.0.0",
    "babel-preset-stage-2": "^6.0.0",
    "babel-register": "^6.0.0",
    "bootstrap-loader": "^2.0.0-beta.9",
    "connect-history-api-fallback": "^1.1.0",
    "css-loader": "^0.23.0",
    "dynamics.js": "^1.1.5",
    "eslint": "^2.10.2",
    "eslint-config-standard": "^5.1.0",
    "eslint-friendly-formatter": "^2.0.5",
    "eslint-loader": "^1.3.0",
    "eslint-plugin-html": "^1.3.0",
    "eslint-plugin-promise": "^1.0.8",
    "eslint-plugin-standard": "^1.3.2",
    "eventsource-polyfill": "^0.9.6",
    "express": "^4.13.3",
    "extract-text-webpack-plugin": "^1.0.1",
    "file-loader": "^0.8.4",
    "function-bind": "^1.0.2",
    "html-webpack-plugin": "^2.8.1",
    "http-proxy-middleware": "^0.12.0",
    "json-loader": "^0.5.4",
    "ora": "^0.2.0",
    "shelljs": "^0.6.0",
    "url-loader": "^0.5.7",
    "vue-hot-reload-api": "^1.2.0",
    "vue-html-loader": "^1.0.0",
    "vue-loader": "^8.3.0",
    "vue-style-loader": "^1.0.0",
    "webpack": "^1.13.2",
    "webpack-dev-middleware": "^1.4.0",
    "webpack-hot-middleware": "^2.6.0",
    "webpack-merge": "^0.8.3"
  }

其中包括了由项目自动生成的一些插件。 
我梳理一下,主要有下面这些,其中标注红色的是我自己用来开发依赖的: 
dependencies: 
babel-runtime 
bootstrap 
bootstrap-table 
font-awesome 
jQuery 
node-glob 
vue 
devDependencies: 
bootstrap-loader 
dynamics.js 
那么主要就是添加一下node-glob和vue,其他的如果需要再进行添加。nodej-glob是用来获取路径的,vue是需要依赖的主要部分。

第四步:修改项目

这一步最重要。 
在我们没有动过之前,src目录是这个样子的,如图5: 
没动过的src 
图5 
首先,创建如下目录结构: 
src 

—–module 

—–index 

—–index.html 
—–main.js 
将之前外面的index.html放进来,main.js放入index,改名为index.js,此处一定注意名称要相同,否则后面寻找路径时是找不到对应文件的。然后将App.vue放入components。最后是这样的,如图6: 
修改之后的src 
图6 
这时候需要对文件进行一定的修改。首先是index.js,对App的调用,路径修改,如图7 
[图片]

[图片] 
图7

修改完了上面的资源,我们要修改webpack的配置。 
我们介绍一下webpack在这个项目中原本的顺序:由于webpack将所有的js,css/less,html等都视为js的可引入资源,所以入口就成了js文件。那么webpack需要设置一个入口的js文件,这个入口的js文件就是main.js,在webpack中有一个插件,叫做html-webpack-plugin,这个是用来将js和html对应起来,也就是若干js对应一个html,在原来的项目中html就是index.html。 
在运行npm run dev 或者build之后,就会将文件打包,由于dev的时候文件是在内存中,所以build可以看得比较清楚,在dist目录中,会有一个index.html,其中已经打包进了

webpack.base.conf

添加下面两行在这里,图8中位置,

var glob = require(\'glob\');
var entries = getEntry(\'./src/module/**/*.js\'); // 获得入口js文件
  • 1
  • 2
  • 1
  • 2

[图片] 
图8 
这里的glob,就是前面提到的node-glob。将entry修改为这个,图9中位置, 
[图片] 
图9

然后在下面添加getEntry方法。

function getEntry(globPath) {
  var entries = {},
    basename, tmp, pathname;

  glob.sync(globPath).forEach(function (entry) {
    basename = path.basename(entry, path.extname(entry));
    tmp = entry.split(\'/\').splice(-3);
    pathname = tmp.splice(0, 1) + \'/\' + basename; // 正确输出js和html的路径
    entries[pathname] = entry;
  });
  console.log("base-entrys:");
  console.log(entries);
  return entries;
}

因为我们的想法是要将所有的业务模块放在module中,这样一来的话,就在module中细分,最后输出html都在dist的module下。这里的字符串操作也是和路径的情况相匹配的,如果有需要进行其他方式的设定,注意在这里修改路径的识别。

webpack.dev.conf.js

在打开后,我们会发现在这里有一个插件的设置,如图10: 
[图片] 
图10 
这个 插件就是刚才提到的将输出html页面build结果的地方。 
首先,添加

var path = require(\'path\');
var glob = require(\'glob\');

用来引入path和glob工具。 
将图10中的那一段去掉,因为我们要自己来添加这个插件。 
同样的,在这个文件中也需要添加这个函数,放在文件的下面,

function getEntry(globPath) {
  var entries = {},
    basename, tmp, pathname;

  glob.sync(globPath).forEach(function(entry) {
    basename = path.basename(entry, path.extname(entry));
    tmp = entry.split(\'/\').splice(-3);
    pathname = tmp.splice(0, 1) + \'/\' + basename; // 正确输出js和html的路径
    entries[pathname] = entry;
  });
  console.log("dev-entrys:");
  console.log(entries);
  return entries;
}

然后再添加这一段,

var pages = getEntry(\'./src/module/**/*.html\');
console.log("dev pages----------------------");
for (var pathname in pages) {
  console.log("filename:" + pathname + \'.html\');
  console.log("template:" + pages[pathname]);
  // 配置生成的html文件,定义路径等
  var conf = {
    filename: pathname + \'.html\',
    template: pages[pathname], // 模板路径
    minify: { //传递 html-minifier 选项给 minify 输出
      removeComments: true
    },
    inject: \'body\', // js插入位置
    chunks: [pathname, "vendor", "manifest"] // 每个html引用的js模块,也可以在这里加上vendor等公用模块
  };
  // 需要生成几个html文件,就配置几个HtmlWebpackPlugin对象
  module.exports.plugins.push(new HtmlWebpackPlugin(conf));
}

这个同样是通过指定的路径,按照我之前的预想,进行html的迭代获取,然后对每一个html进行设定。我们的多页面输出关键也就在这个地方。 
html-webpack-plugin这个插件可以为一个html输出打包对应的js模块。chunks就是对应的js模块,也就是webpack的入口,包括entries和使用了webpack.optimize.CommonsChunkPlugin插件声称的公共js模块。这些模块都有各自的名字,entries的名字就是前面通过getEntry函数生成的一组入口组件名称和路径。 
通过上面的修改,就做成了这样一件事情:为webpack提供多个js入口,而这些js入口和html页面是在同一个文件夹下的,那么它们的key或者说name就是相同的。这样在循环的时候,就会获取到对应的js和html,通过循环创建多个html-webpack-plugin来将不同的js模块打包进对应的html,并通过webpack批量构建,在dist中就会产生我们需要的一组html文件。而这些html文件都是已经经过压缩的,js代码也经过了压缩处理。

webpack.prod.conf.js

和webpack.dev.conf.js中做类似的处理,先注释掉原来的HtmlWebpackPlugin,然后在下面添加函数,通过迭代插入多个HtmlWebpackPlugin。

HtmlWebpackPlugin更多的设置,到webpack的官网上查看。

然后使用npm run dev或者npm run build来构建。在构建的过程中,可能会出现一些依赖插件不存在的错误,需要先使用npm install –save-dev 插件名 来安装相应的依赖插件。

这样,index.html就被构建到了dist/module/index.html中。 
但功能是一模一样的。 
vue的使用在这里不赘述。这里说明一下,我们的module中,是系统的业务模块,components中是功能模块和细分的代码模块,也就是vue组件。由于webpack这里带了babel,所以在js源文件中可以使用ES6的写法。在业务js中,就可以通过导入,组合,自定义vue组件,来实现相应的业务需求。

其他

比如在我现在拆分的这个网页中,包括这么几个部分: 
[图片]

[图片]

[图片] 
这是对一个bootstrap网站模板index页面进行拆分后的结果,css,html都放在对应的vue中,当然,我也引入了jquery。 
vue的组件可以实现继承和mixin。能够很好的进行组件化开发,而通过webpack将src的源代码进行构建变成浏览器能够识别的正常文件。这样就大大降低了前端开发的重复性。

/2016-09-13 补 / 
这个是我的一个demo,提供给学生用的。 
http://www.huyangsheng.cn/resource/vue-multipage-demo.rar

以上文章是参考了几篇之后弄出来一个适合自己用的。 
参考: 
https://github.com/Coffcer/Blog/issues/1 
http://cnu4.github.io/2016/03/21/Webpack-Vue-MultiplePage/ 
http://jiongks.name/blog/just-vue/?from=groupmessage&isappinstalled=1 
http://www.cnblogs.com/grimm/p/5768433.html 
https://github.com/yaoyao1987/vue-cli-multipage

---------------------转发结束--------------------

以上是关于使用vue+webpack的多页面架构(转+自己的情况)的主要内容,如果未能解决你的问题,请参考以下文章

Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(上篇——纯前端多页面)

[转] vue&webpack多页面配置

进阶| Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(上篇)

webpack的多文件打包问题

vue3多页面运行与打包

[转] Vue + Webpack 组件式开发(练习环境)