详解如何快速配置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选择没有colspan属性的td的代码
Jul 06 Javascript
js中继承的几种用法总结(apply,call,prototype)
Dec 26 Javascript
购物车选中得到价格实现示例
Jan 26 Javascript
浅谈javascript中的instanceof和typeof
Feb 27 Javascript
js实现兼容IE和FF的上下层的移动
May 04 Javascript
JavaScript识别网页关键字并进行描红的方法
Nov 09 Javascript
js跨域请求数据的3种常用的方法
Dec 01 Javascript
详解vuex 中的 state 在组件中如何监听
May 23 Javascript
vue-cli脚手架引入弹出层layer插件的几种方法
Jun 24 Javascript
js实现鼠标点击飘爱心效果
Aug 19 Javascript
一分钟学会JavaScript中的try-catch
Dec 14 Javascript
canvas绘制折线路径动画实现
May 12 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
从零开始学YII2框架(四)扩展插件yii2-kartikgii
2014/08/20 PHP
详解Laravel服务容器的绑定与解析
2019/11/05 PHP
javascript中onmouse事件在div中失效问题的解决方法
2012/01/09 Javascript
用js实现输入提示(自动完成)的实例代码
2013/06/14 Javascript
如何在JavaScript中实现私有属性的写类方式(一)
2013/12/04 Javascript
JS的location.href跳出框架打开新页面的方法
2014/09/04 Javascript
javascript中局部变量和全局变量的区别详解
2015/02/27 Javascript
jquery获取点击控件的绝对位置简单实例
2016/10/13 Javascript
微信小程序遇到修改数据后页面不渲染的问题解决
2017/03/09 Javascript
jQuery实现返回顶部按钮和scroll滚动功能[带动画效果]
2017/07/05 jQuery
angularjs实现天气预报功能
2020/06/16 Javascript
vue.js前后端数据交互之提交数据操作详解
2018/04/24 Javascript
React Native日期时间选择组件的示例代码
2018/04/27 Javascript
Chart.js 轻量级HTML5图表绘制工具库(知识整理)
2018/05/22 Javascript
ES6的异步操作之promise用法和async函数的具体使用
2019/12/06 Javascript
解决Vue 移动端点击出现300毫秒延迟的问题
2020/07/21 Javascript
[01:04:31]DOTA2-DPC中国联赛定级赛 iG vs Magma BO3第二场 1月8日
2021/03/11 DOTA
python使用插值法画出平滑曲线
2018/12/15 Python
python3.x 生成3维随机数组实例
2019/11/28 Python
Python通过Tesseract库实现文字识别
2020/03/05 Python
解决jupyter运行pyqt代码内核重启的问题
2020/04/16 Python
Python使用正则表达式实现爬虫数据抽取
2020/08/17 Python
Python如何使用ElementTree解析xml
2020/10/12 Python
python利用pytesseract 实现本地识别图片文字
2020/12/14 Python
Python .py生成.pyd文件并打包.exe 的注意事项说明
2021/03/04 Python
css3背景_动力节点Java学院整理
2017/07/11 HTML / CSS
CSS3中线性颜色渐变的一些实现方法
2015/07/14 HTML / CSS
美国生日蛋糕店:Bake Me A Wish!
2017/02/08 全球购物
Napapijri西班牙在线商店:夹克、外套、运动衫等
2020/11/05 全球购物
实习护士自我鉴定
2013/10/13 职场文书
后勤人员岗位职责
2013/12/17 职场文书
军训学生自我鉴定
2014/02/12 职场文书
4s店活动策划方案
2014/08/25 职场文书
安全生产先进个人总结
2015/02/15 职场文书
公司新员工欢迎词
2015/09/30 职场文书
叶县这家生产军用电台的兵工厂,人称“四机部”,走出一上将
2022/02/18 无线电