详解如何快速配置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 相关文章推荐
Jquery Autocomplete 结合asp.net使用要点
Oct 29 Javascript
改变隐藏的input中value值的方法
Mar 19 Javascript
jQuery进行组件开发完整实例
Dec 15 Javascript
js获取所有checkbox的值的简单实例
May 30 Javascript
JavaScript prototype属性详解
Oct 25 Javascript
AngularJS打开页面隐藏显示表达式用法示例
Dec 25 Javascript
Bootstrap表单使用方法详解
Feb 17 Javascript
令按钮悬浮在(手机)页面底部的实现方法
May 02 Javascript
Vue computed计算属性的使用方法
Jul 14 Javascript
从零撸一个pc端vue的ui组件库( 计数器组件 )
Aug 08 Javascript
微信小程序后端实现授权登录
Feb 24 Javascript
vue+elementui 实现新增和修改共用一个弹框的完整代码
Jun 08 Vue.js
详解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
php构造函数实例讲解
2013/11/13 PHP
php calender(日历)二个版本代码示例(解决2038问题)
2013/12/24 PHP
php生成圆角图片的方法
2015/04/07 PHP
深入document.write()与HTML4.01的非成对标签的详解
2013/05/08 Javascript
如何使用jquery控制CSS样式,并且取消Css样式(如背景色,有实例)
2013/07/09 Javascript
js获取通过ajax返回的map型的JSONArray的方法
2014/01/09 Javascript
Javascript添加监听与删除监听用法详解
2014/12/19 Javascript
NodeJS制作爬虫全过程
2014/12/22 NodeJs
JavaScript多并发问题如何处理
2015/10/28 Javascript
Bootstrap入门书籍之(三)栅格系统
2016/02/17 Javascript
js仿3366小游戏选字游戏
2016/04/14 Javascript
jQuery制作图片旋转效果
2017/02/02 Javascript
JS控件bootstrap suggest plugin使用方法详解
2017/03/25 Javascript
JS中使用正则表达式g模式和非g模式的区别
2017/04/01 Javascript
jQuery获取复选框选中的当前行的某个字段的值
2017/09/15 jQuery
React Native 搭建开发环境的方法步骤
2017/10/30 Javascript
深入理解Vue官方文档梳理之全局API
2017/11/22 Javascript
axios发送post请求springMVC接收不到参数的解决方法
2018/03/05 Javascript
浅谈Webpack 持久化缓存实践
2018/03/22 Javascript
vue.js添加一些触摸事件以及安装fastclick的实例
2018/08/28 Javascript
前端js中的事件循环eventloop机制详解
2019/05/15 Javascript
p5.js临摹动态图形的方法
2019/10/23 Javascript
Python爬虫爬验证码实现功能详解
2016/04/14 Python
文件上传服务器-jupyter 中python解压及压缩方式
2020/04/22 Python
CSS3田字格列表的样式编写方法
2018/11/22 HTML / CSS
Ralph Lauren拉夫·劳伦美国官网:带有浓郁美国气息的高品味时装品牌
2017/11/01 全球购物
Tory Burch英国官方网站:美国时尚生活品牌
2017/12/06 全球购物
英国受欢迎的运动鞋和街头服装商店:Footasylum
2018/06/12 全球购物
台湾三立电视电商平台:电电购
2019/09/09 全球购物
法学个人求职信范文
2014/01/27 职场文书
2014年销售人员工作总结
2014/11/27 职场文书
班主任远程培训研修日志
2015/11/13 职场文书
中职班主任培训心得体会
2016/01/07 职场文书
抖音短视频(douyin)去水印工具的实现代码
2021/03/30 Javascript
SQL SERVER中的流程控制语句
2022/05/25 SQL Server