详解如何快速配置webpack多入口脚手架


Posted in Javascript onDecember 28, 2018

背景

当我们基于vue开发单个项目时,我们会init一个vue-cli,但当我们想在其他项目里共用这套模板时,就需要重新init一个,或者clone过来,这非常不方便,而且当多人开发时,我们希望所有的开发代码都在一个git目录下,这时就有了对webpack进行配置的需求,当有些页面需要多入口时,我们又产生了对多入口配置的需求,这里提供一种配置方案,希望能帮助到有需要的人,废话不多说,我们开始吧!

先初始化一个项目

我们通过vue init webpack demo 生成的文件目录是这样的

详解如何快速配置webpack多入口脚手架

修改项目入口

要改多入口,首先改造一下 webpack.base.conf.js 中的 contextentry

context:基础目录,绝对路径,用于从配置中解析入口起点(entry point)和 loader。

entry:起点或是应用程序的起点入口。从这个起点开始,应用程序启动执行。

module.exports = {
 context: path.resolve(__dirname, '../'),
 entry: {
  app: './src/main.js'
 },
};

如果项目只有一个入口,那么直接在这里改entry就可以了,但一般我们都是多个项目在放一个目录里,所以要提取出来context和entry。

const paths = require('./paths')
const rootPath = paths.rootPath
module.exports = {
 context: rootPath
 entry: {
  app: utils.getEntry(),
 }, 
};

在config里新建 _config.js 和 paths.js

_config.js ,用于设置当前启动项目,并将这个文件添加到.gitignore中,因为以后多人开发都是在本地修改项目地址。

'use strict'
 module.exports = {
 appName: 'mobile',
 projectName: 'demo'
}

这里设计2个目录,appName是src下的一级目录,projectName是appName下的二级目录,目的在于方便拓展,比如公司的项目分为pc项目和mobile项目,开发时便于区分,如果你的项目比较少,那可以把appName写成一个固定字符串如:pages,每次切换项目只更改projectName就可以了。我们将所有项目放在src下,类似目录如下

├─mobile
│ ├─demo
│ └─demo2
└─pc
  ├─demo
  └─demo2

paths.js ,用于配置一些全局需要用到的路径

'use strict'
const path = require('path')
const fs = require('fs')
const _config = require('./_config')

const rootPath = fs.realpathSync(process.cwd()) // 项目根目录 fs.realpathSync表示获取真实路径
const resolve = relativePath => path.resolve(rootPath, relativePath) // 自定义一个resolve函数,拼接出需要的路径地址
module.exports = {
 rootPath, // 项目根目录
 commonPath: resolve('common'), // 公共目录
 projectPath: resolve(`src/${_config.appName}/${_config.projectName}`), // 子项目根目录
 config: resolve('config'), // 项目配置
 static: resolve('static') // 公共静态资源目录
}

新建common文件夹

我们在src同级新建一个common文件夹,用于存放静态资源及公共组件

-components 
 ├─assets
 ├─components
 └─xhr

assets里可以存放公共样式css,公共字体font,公共图片img,公共方法js等;components里存放提取出来的公共组件,xhr我放的是axio的封装,整个文件夹可以自定义修改,这里就不展开了,如果项目比较简单不需要,在paths.js里删去对应的部分即可。

再来看我们修改的entry,我们在config文件夹中的utils.js 新增了getEntry方法,并在entry处引用。

'use strict'
// 省略...
const paths = require('./paths')
const fs = require('fs')
// 省略...
exports.getEntry = () => {
 const entryPath = path.resolve(paths.projectPath, 'entry')
 const entryNames = fs
   .readdirSync(entryPath)
   .filter(n => /\.js$/g.test(n))
   .map(n => n.replace(/\.js$/g, ''))
 const entryMap = {}

 entryNames.forEach(
   name =>
   (entryMap[name] = [
     ...['babel-polyfill', path.resolve(entryPath, `${name}.js`)]
   ])
 )
 return entryMap
}

实际上就是对当前项目entry文件中的js文件进行遍历,如果是单个就是单入口,多个就是多入口。

创建2个项目

详解如何快速配置webpack多入口脚手架

  • assets 静态资源
  • config.js 代理配置、打包地址等配置
  • entry 入口文件夹

demo1是一个单入口项目,demo2是一个多入口项目,如果是多入口项目,需要在entry增加对应的js文件,如上图中的more.html和more.js,上面的getEntry其实找的就是index.js和more.js。

我们再看一下demo2中entry中的index.js和more.js

// index.js
import Vue from 'vue'
import App from '../App'

new Vue({
 el: '#app',
 router,
 components: { App },
 template: '<App/>'
})
// more.js
import Vue from 'vue'
import App from '../More'

new Vue({
 el: '#more',
 components: { App },
 template: '<App/>'
})

引入对应的组件就好,再看下config.js

const host = 'http://xxx.com/api' // 测试地址

module.exports = {
 dev: {
  // proxy代理配置
  proxyTable: {
   '/api': {
    target: host, // 源地址
    changeOrigin: true, // 改变源
    logLevel: 'debug',
    ws: true,
    pathRewrite: {
     '^/api': '' // 路径重写
    }
   }
  },
  build: {
   // build输出路径
   // assetsRoot: path.resolve(process.cwd(), '')
  }
  // 是否启用postcss-pxtorem插件 https://github.com/cuth/postcss-pxtorem
  // pxtorem: true
 }
}

这里就是根据需要自行配置了,如果不需要完全可以不要这个文件,重要的还是entry的入口文件。

打包出口配置

入口改好了,我们再看出口,找到如下内容

// webpack.dev.conf.js
plugins: [
  new webpack.DefinePlugin({
   'process.env': require('../config/dev.env')
  }),
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
  new webpack.NoEmitOnErrorsPlugin(),
  // https://github.com/ampedandwired/html-webpack-plugin
  new HtmlWebpackPlugin({
   filename: 'index.html',
   template: 'index.html',
   inject: true
  }),
  // copy custom static assets
  new CopyWebpackPlugin([
   {
    from: path.resolve(__dirname, '../static'),
    to: config.dev.assetsSubDirectory,
    ignore: ['.*']
   }
  ])
 ]
// webpack.prod.conf.js
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'
  }),
// 省略
// copy custom static assets
  new CopyWebpackPlugin([
   {
    from: path.resolve(__dirname, '../static'),
    to: config.build.assetsSubDirectory,
    ignore: ['.*']
   }
  ])

HtmlWebpackPlugin的作用是生成一个 HTML5 文件,CopyWebpackPlugin的作用是将单个文件或整个目录复制到构建目录。我们在utils.js中新建2个方法getHtmlWebpackPlugin和getCopyWebpackPlugin,对这两个方法进行替换,让他们支持多入口。改动后如下

// webpack.dev.conf.js
 plugins: [
  new webpack.DefinePlugin({
   'process.env': require('./dev.env')
  }),
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update.
  new webpack.NoEmitOnErrorsPlugin(),
  // https://github.com/ampedandwired/html-webpack-plugin
  // 改动
  ...utils.getHtmlWebpackPlugin(baseWebpackConfig),
  // copy custom static assets
  // 改动
  ...utils.getCopyWebpackPlugin()
 ]
// webpack.prod.conf.js
  // 改动
   ...utils.getHtmlWebpackPlugin(baseWebpackConfig),
  // 省略
  // 改动
   ...utils.getCopyWebpackPlugin()
// utils.js
exports.getHtmlWebpackPlugin = baseWebpackConfig => {
 const HtmlWebpackPluginList = []
 const entryNames = Object.keys(baseWebpackConfig.entry)
 entryNames.forEach(name => {
   HtmlWebpackPluginList.push(
     new HtmlWebpackPlugin(
       Object.assign({
           filename: config.build.filename && process.env.NODE_ENV == 'production' ? config.build.filename : `${name}.html`,
           template: config.build.template && process.env.NODE_ENV == 'production' ? path.resolve(
             paths.projectPath, config.build.template) : path.resolve(
             paths.projectPath,
             `${name}.html`
           ),
           inject: true,
           excludeChunks: entryNames.filter(n => n !== name)
         },
         process.env.NODE_ENV === 'production' ? {
           minify: {
             removeComments: true,
             collapseWhitespace: true
               // removeAttributeQuotes: true
           },
           chunksSortMode: 'dependency'
         } : {}
       )
     )
   )
 })
 return HtmlWebpackPluginList
}

exports.getCopyWebpackPlugin = () => {
 const projectStaticPath = path.resolve(paths.projectPath, 'static')
 const assetsSubDirectory =
   process.env.NODE_ENV === 'production' ?
   config.build.assetsSubDirectory :
   config.dev.assetsSubDirectory
 const rootConfig = {
   from: paths.static,
   to: assetsSubDirectory,
   ignore: ['.*']
 }
 const projectConfig = {
   from: projectStaticPath,
   to: assetsSubDirectory,
   ignore: ['.*']
 }
 return [
   new CopyWebpackPlugin(
     fs.existsSync(projectStaticPath) ? [rootConfig, projectConfig] : [rootConfig]
   )
 ]
}

修改index.js

我们找到config里index.js,对其做一些修改,让我们可以在项目里的config.js中配置代理,打包目录,让模板更灵活。

// config/index.js 改造前
 dev: {
  // Paths
  assetsSubDirectory: 'static',
  assetsPublicPath: '/',
  proxyTable: {},
  // Various Dev Server settings
  host: 'localhost', // can be overwritten by process.env.HOST 
 },
 build: {
  // Template for index.html
  index: path.resolve(__dirname, '../dist/index.html'),

  // Paths
  assetsRoot: path.resolve(__dirname, '../dist'),
  assetsSubDirectory: 'static',
  assetsPublicPath: '/',
  // 省略
 }
//config/index.js 改造后
const paths = require('./paths')
const resolve = relativePath => path.resolve(paths.projectPath, relativePath)
const _config = require(resolve('config.js')) // 子项目webpack配置
 dev: {
  // Paths
  assetsSubDirectory: 'static',
  assetsPublicPath: '/',
  proxyTable: _config.dev.proxyTable,
  // Various Dev Server settings
  host: '0.0.0.0', // can be overwritten by process.env.HOST 
 },
 build: {
  // Template for index.html
  index: path.resolve(__dirname, '../dist/index.html'),

  // Paths
  assetsRoot: _config.build.assetsRoot || path.resolve(__dirname, '../dist'),
  assetsSubDirectory: 'static',
  assetsPublicPath: _config.build.publichPath || './',
  // 省略
 }

到这里,我们的多入口配置就基本完成了,注意修改过的配置文件里一些引用需要加上,检查下路径是否正确。

既然我们的目的就是打造多入口模板,那么以demo2为例,运行npm run dev 在如果服务是http://localhost:8080,多页面入口在浏览器访问时url就是http://localhost:8080/more.html。注意要带.html哦。

运行npm run build 我们会发现dist文件夹里有2个html,说明多入口打包成功

详解如何快速配置webpack多入口脚手架

到此我们的项目模板就配置完成了。以后多人开发、多入口活动都可以在这个项目下进行开发了,此篇不涉及webpack优化,只提供一种配置思路。如果感觉文章写的不够清楚,或者想直接使用这个模板,我的git上有完整的脚手架

传送门 ,如果遇到问题或者好的建议,欢迎提出。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
页面只有一个text的时候,回车自动submit的解决方法
Aug 12 Javascript
extjs grid设置某列背景颜色和字体颜色的方法
Sep 03 Javascript
jquery 通过name快速取值示例
Jan 24 Javascript
js实现日历可获得指定日期周数及星期几示例分享(js获取星期几)
Mar 14 Javascript
JavaScript中利用各种循环进行遍历的方式总结
Nov 10 Javascript
理解JavaScript中worker事件api
Dec 25 Javascript
vue Element-ui input 远程搜索与修改建议显示模版的示例代码
Oct 19 Javascript
vue keep-alive请求数据的方法示例
May 16 Javascript
Vue中使用vux配置代码详解
Sep 16 Javascript
JavaScript函数式编程(Functional Programming)声明式与命令式实例分析
May 21 Javascript
elementUI vue this.$confirm 和el-dialog 弹出框 移动 示例demo
Jul 03 Javascript
在webstorm中配置less的方法详解
Sep 25 Javascript
详解puppeteer使用代理
Dec 27 #Javascript
Angular(5.2-&gt;6.1)升级小结
Dec 27 #Javascript
详解angular2 控制视图的封装模式
Dec 27 #Javascript
JavaScript原型对象原理与应用分析
Dec 27 #Javascript
angular6 填坑之sdk的方法
Dec 27 #Javascript
react+ant design实现Table的增、删、改的示例代码
Dec 27 #Javascript
React降级配置及Ant Design配置详解
Dec 27 #Javascript
You might like
destoon二次开发入门示例
2014/06/20 PHP
php利用cookies实现购物车的方法
2014/12/10 PHP
javascript在一段文字中的光标处插入其他文字
2007/08/26 Javascript
ExtJS 设置级联菜单的默认值
2010/06/13 Javascript
浅析offsetLeft,Left,clientLeft之间的区别
2013/11/30 Javascript
JavaScript排序算法之希尔排序的2个实例
2014/04/04 Javascript
JavaScript中字符串(string)转json的2种方法
2015/06/25 Javascript
细数JavaScript 一个等号,两个等号,三个等号的区别
2016/10/09 Javascript
JSON 数据详解及实例代码分析
2017/01/20 Javascript
老生常谈js数据类型
2017/08/03 Javascript
JavaScript使用Ajax上传文件的示例代码
2017/08/10 Javascript
Javascript(es2016) import和require用法和区别详解
2017/08/11 Javascript
ES6中的Promise代码详解
2017/10/09 Javascript
vue3.0 CLI - 2.3 - 组件 home.vue 中学习指令和绑定
2018/09/14 Javascript
[48:41]VP vs VG Supermajor小组赛 B组胜者组决赛 BO3 第二场 6.2
2018/06/03 DOTA
python打开url并按指定块读取网页内容的方法
2015/04/29 Python
python检查指定文件是否存在的方法
2015/07/06 Python
Python实现包含min函数的栈
2016/04/29 Python
如何在Python函数执行前后增加额外的行为
2016/10/20 Python
python实现机械分词之逆向最大匹配算法代码示例
2017/12/13 Python
Python编写Windows Service服务程序
2018/01/04 Python
Python连接Mssql基础教程之Python库pymssql
2018/09/16 Python
解决Ubuntu18中的pycharm不能调用tensorflow-gpu的问题
2020/09/17 Python
python3 re返回形式总结
2020/11/20 Python
python的setattr函数实例用法
2020/12/16 Python
python字典与json转换的方法总结
2020/12/28 Python
HTML5表格_动力节点Java学院整理
2017/07/11 HTML / CSS
几个人围成一圈的问题
2013/09/26 面试题
.NET现在共支持多少种语言
2014/02/26 面试题
2014年村官工作总结
2014/11/24 职场文书
客房服务员岗位职责
2015/02/09 职场文书
医药公司采购员岗位职责
2015/04/03 职场文书
大队委员竞选稿
2015/11/20 职场文书
如何使用vue3打造一个物料库
2021/05/08 Vue.js
JavaScript高级程序设计之基本引用类型
2021/11/17 Javascript
html中两种获取标签内的值的方法
2022/06/16 jQuery