欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-30 22:21:00
背景 当我们基于vue开发单个项目时,我们会init一个vue-cli,但当我们想在其他项目里共用这套模板时,就需要重新init一个,或者clone过来,这非常不方便,而...

背景

当我们基于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上有完整的脚手架

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

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