本文主要跟你们分享一下如何使用webpack4来一步一步搭建本身的项目框架。若是没接触过webpack,或者不是很了解,建议在阅读本文以前先去webpack 中文网了解一下基本概念、核心理念 入口(entry)、输出(output)、loader、插件(plugins)等知识。javascript
主要功能:
一、支持VUE
二、支持React
三、支持less、scss
四、图片压缩,css分离
五、px转rem
六、ES6
七、打包后自动压缩zip文件
八、支持本地调试
九、支持本地mock数据服务
复制代码
我负责的主要是用于各类节日活动的H5项目,项目比较独立,周期比较短,以前每一个项目一个开发人员就能够搞定,可是随着公司发展,如今作的活动愈来愈复杂,每一个项目须要的人员也随之增长,可是你们的技术栈不同,有人用zepto.js,有人用vue,有人用react,有人习惯原始的css,有人喜欢less、scss,在项目中,为了让你们都还使用本身擅长的技术栈来开发,带着这样的目的,从而从0到1,慢慢搭建起本身的项目框架,目前框架已生成脚手架,发布到npm,有兴趣的同窗能够安装体验一下。css
使用步骤:
一、安装脚手架,执行 npm install light-app-cli -g
二、建立项目,执行light-app-cli <项目名称>
三、详见 [GitHub地址](https://github.com/hanhan3682523/light-app-cli)
复制代码
环境要求:
一、node >= 10.5.0,[node下载地址]: https://nodejs.org/en/download/
二、webpack >=4.16.0,安装:npm install -g webpack
三、框架目录结构预览
搭建流程:
一、目录及文件说明
二、配置入口(entry)
三、配置出口(output)
四、配置loader
五、配置插件(plugins)
六、开发环境配置devSever
复制代码
一、目录及文件说明html
|- build
-- webpack.base.conf.js--开发和打包用到的公用配置项,经过webpack-merge 分别使用
-- webpack.build.config.js--打包配置
-- webpack.dev.config.js--开发配置,生成本地服务,设置访问域名、热替换、代理、端口等信息
-- webpack.plugins.js--配置webpack插件
-- webpack.rules.js--配置webpack loader,进行文件处理
|- config
-- index.js--本地服务域名、端口等配置
|- dist
|- mock
-- data.js--设置mock接口数据
-- server.js--本地mock服务
|- src
|- assets
|- css
|- image
|- js
-- index.html
|- zip
|- .babelc
|- package.json
|- postcss.config.js
|- tsconfig.json
复制代码
二、配置入口(entry)vue
项目为多页面应用,会涉及到多个入口,因此咱们进行约定,全部入口文件统一放到src目录下的js文件夹中,利用globby模块,读取js文件夹下的全部js名称(不包括子文件夹),从而返回一个入口(entry)对象。java
//读取文件
const glob = require('globby');
let entryConfig = (function() {
let _config = {};
//选择js目录下的文件,不包含common中的js做为入口
const fileList = glob.sync(['./src/js/*.*']);
console.info('tag', fileList);
if (fileList && fileList.length > 0) {
for (let i = 0; i < fileList.length; i++) {
_config[fileList[i].match(/([^\/]+)(?=\.)/ig)[0]] = fileList[i];
}
}
return _config;
})();
//入口
entry: entryConfig,
复制代码
三、配置出口(output)node
在filename中添加了hash命名,目的是为了防止cdn缓存、浏览器缓存,每次打包,都会对静态资源从新命名,这样修改发布后,只须要推html的缓存便可。react
//出口
output: {
filename: 'js/[name][hash].js',
path: config.build.assetsRoot,
publicPath: process.env.NODE_ENV === 'production' ?
config.build.assetsPublicPath :
config.dev.assetsPublicPath
},
复制代码
四、配置loaderwebpack
项目中文件类型较多,每种文件类型都有专门的loader进行处理,涉及的loader比较多,因此把loader统一放到webpack.rules.js中进行管理,方便维护和扩展。git
//loader,rulesConfig内容详见下面webpack.rules.js
module: {
rules: rulesConfig
},
//webpack.rules.js 中内容
/* 做者:飘落的枫叶 说明:配置webpack打包loader加载器 日期:2018.6.1 */
const path = require('path');
const extractTextPlugin = require("extract-text-webpack-plugin");
function resolve(dir) {
return path.join(__dirname, '..', dir)
}
module.exports = [{
test: /\.vue$/,
use: {
loader: 'vue-loader'
},
//加快搜索速度
exclude: resolve('node_modules'),
}, {
test: /\.ts$/,
use: {
loader: 'ts-loader'
},
//加快搜索速度
exclude: resolve('node_modules'),
}, {
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react'],
plugins: ['transform-runtime'],
cacheDirectory: true
}
},
exclude: resolve('node_modules'),
}, {
test: /\.css$/,
use: extractTextPlugin.extract({
fallback: "style-loader",
use: ["css-loader", "postcss-loader"],
// css中的基础路径
publicPath: "../"
})
}, {
test: /\.((woff2?|svg)(\?v=[0-9]\.[0-9]\.[0-9]))|(woff2?|svg|jpe?g|png|gif|ico)$/,
use: [{
loader: 'url-loader',
options: {
limit: 8192, //设置转换成base64的大小
name: '[name][hash:8].[ext]',
outputPath: 'image/'
}
}],
//只命中src目录中的文件,加快搜索速度
include: resolve('src')
}, {
test: /\.(html)$/,
use: {
loader: 'html-loader'
},
//只命中src目录中的文件,加快搜索速度
include: resolve('src')
}, {
test: /\.less$/,
use: extractTextPlugin.extract({
fallback: "style-loader",
use: ["css-loader", "postcss-loader", "less-loader"],
// css中的基础路径
publicPath: "../"
}),
//只命中src目录中的文件,加快搜索速度
include: resolve('src')
}, {
test: /\.(scss|sass)$/,
// 分离的写法
use: extractTextPlugin.extract({
fallback: "style-loader",
use: ["css-loader", "postcss-loader", "sass-loader"],
// css中的基础路径
publicPath: "../"
}),
//只命中src目录中的文件,加快搜索速度
include: resolve('src')
}];
复制代码
五、配置插件(plugins)github
插件能够自定义webpack的构建过程,webpack自己也内置了一些插件。同loader同样,为了便于管理,咱们把插件统一放到webpack.plugins.js中进行管理,这里面使用插件主要用于分离css文件,处理vue文件,以及打包后自动压缩zip文件等。
//插件,pluginsConfig内容见下面webpack.plugins.js
plugins: pluginsConfig
//webpack.plugins.js
/* 做者:飘落的枫叶 说明:配置webpack打包插件 日期:2018.6.1 */
//配置文件
const config = require('../config/index')
//路徑
const path = require('path');
// html模板
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 清除目录等
const CleanWebpackPlugin = require('clean-webpack-plugin');
// 分离css
const extractTextPlugin = require("extract-text-webpack-plugin");
//静态资源输出
const copyWebpackPlugin = require("copy-webpack-plugin");
//css压缩
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
//vue插件
const VueLoaderPlugin = require('vue-loader/lib/plugin');
//打包文件
const FileManagerPlugin = require('filemanager-webpack-plugin');
//读取文件
var glob = require('globby');
//webpack
const webpack = require('webpack');
var pluginsConfig = [
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
// 调用以前先清除
new CleanWebpackPlugin(['dist', 'zip'], {
root: path.resolve(__dirname, "..")
}),
//vue插件
new VueLoaderPlugin(),
//静态资源输出
new copyWebpackPlugin([{
from: path.resolve(__dirname, "../src/assets"),
to: './assets'
}]),
// 分离css插件参数为提取出去的路径
new extractTextPlugin({
filename: 'style/[name][hash].css',
}),
//css进行压缩
new OptimizeCssAssetsPlugin({
//assetNameRegExp: /\.style\.css$/g,
cssProcessor: require('cssnano'),
cssProcessorOptions: {
discardComments: {
removeAll: true
}
},
canPrint: true
})
];
(function() {
const fileList = glob.sync(['./src/*.html']);
if (fileList && fileList.length > 0) {
for (var i = 0; i < fileList.length; i++) {
pluginsConfig.push(
new HtmlWebpackPlugin({
template: fileList[i],
filename: fileList[i].match(/([^\/]+)(?=\.)/ig)[0] + '.html',
chunks: [fileList[i].match(/([^\/]+)(?=\.)/ig)[0]],
hash: false, //引入的文件设置hash值
})
);
}
}
})();
//自动压缩dist 到zip文件
//环境判断
if (process.env && process.env.NODE_ENV && process.env.NODE_ENV.trim() === "production" && config.build.zipName) {
// 调用以前先清除
pluginsConfig.push(new CleanWebpackPlugin(['zip']));
let _zipfilename = config.build.zipName;
pluginsConfig.push(new FileManagerPlugin({
onEnd: {
//c
mkdir: ['./zip', './tempzip/' + _zipfilename],
copy: [{
source: './dist',
destination: './tempzip/' + _zipfilename
}, ],
archive: [{
source: './tempzip/',
destination: './zip/' + _zipfilename + '.zip'
}],
delete: [
'./tempzip/'
]
}
}));
}
module.exports = pluginsConfig;
复制代码
六、开发环境配置devSever
项目开发过程当中,为了便于开发调试,咱们须要设置本地开发环境,起http服务,支持自动打开浏览器,文件修改后自动刷新或热更新页面,https,接口请求代理等功能。
const config = require('../config/index')
const common = require('./webpack.base.conf');
const merge = require('webpack-merge');
module.exports = merge(common, {
mode: 'development',
//生成map文件,供调试
devtool: 'eval-source-map',
//监听文件更新,在文件发生变化时从新编译,使用 DevServer 时,监听模式默认是开启的。
watch: true,
//控制监听模式
watchOptions: {
// 不监听的文件或文件夹,支持正则匹配
ignored: /node_modules/,
// 监听到变化发生后会等300ms再去执行动做,防止文件更新太快致使从新编译频率过高,默认为 300ms
aggregateTimeout: 300,
// 判断文件是否发生变化是经过不停的去询问系统指定文件有没有变化实现的,默认每秒轮询1000次
poll: 1000
},
//http服务设置
devServer: {
//代理
proxy: {
'/api': 'http://127.0.0.1:9001',
changeOrigin: true
},
//运行目录
contentBase: './',
//一切服务都启用gzip 压缩:
compress: true,
//端口号
port: config.dev.port || '8080',
//自动打开浏览器
open: true,
//模块热替换
hot: true,
//页面自动刷新
inline: true,
//打开的页面
openPage: '',
//host:'0.0.0.0'--别人能够访问
host: config.dev.host || 'hxj.com',
//支持https
https: config.dev.https,
}
});
复制代码
源码地址