本文主要跟你們分享一下如何使用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,
}
});
複製代碼
源碼地址