tag:crieit.net,2005:https://crieit.net/tags/webpack-stream/feed
「webpack-stream」の記事 - Crieit
Crieitでタグ「webpack-stream」に投稿された最近の記事
2021-01-27T00:00:53+09:00
https://crieit.net/tags/webpack-stream/feed
tag:crieit.net,2005:PublicArticle/16653
2021-01-27T00:00:53+09:00
2021-01-27T00:00:53+09:00
https://crieit.net/posts/webpack-dynamically-change-entrypoint-20210121
Webpack (webpack-stream) で エントリーポイントを動的に変更する
<p>Scss に続いて JS でも動的に読み込むファイルを切り替えたいと考えました。</p>
<h2 id="今回の方法"><a href="#%E4%BB%8A%E5%9B%9E%E3%81%AE%E6%96%B9%E6%B3%95">今回の方法</a></h2>
<h3 id="ディレクトリ構造"><a href="#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E6%A7%8B%E9%80%A0">ディレクトリ構造</a></h3>
<p>サンプルとして、以下のようなディレクトリ構造にしたとします。</p>
<pre><code> /
├ dist/
│ └ js/
│ ├ app.min.js // app.js からビルド
│ └ parts.min.js // parts/ ディレクトリ下のjsをバンドル
└ src/
└ js/
├ app.js
│
└ parts/
├ parts1.js // 単独
├ parts2.js // parts3.js に依存
└ parts3.js
</code></pre>
<ul>
<li><code>src/js/app.js</code>: (存在すれば)常に出力、通常の処理
<ul>
<li><code>dist/js/app.min.js</code> にビルド</li>
</ul></li>
<li><code>src/js/parts/</code>ディレクトリ下: フラグによって動的に読み込むファイルを切り替える
<ul>
<li><code>dist/js/parts.min.js</code> にバンドル</li>
</ul></li>
</ul>
<p>状況的にはこのようにしたいと考えています。</p>
<h3 id="webpack.config.js"><a href="#webpack.config.js">webpack.config.js</a></h3>
<p>以上を踏まえて <code>webpack.config.js</code> 。</p>
<pre><code class="javascript">const webpackTerser = require('terser-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const path = require('path');
const glob = require('glob');
const devFlag = true;
// dynamic import test
const partsPath = 'src/js/parts';
const flag = {
parts1: true,
parts2: true
};
const entry = () => {
const entries = glob
.sync(
'**/*.js',
{
cwd: 'src/js',
//ignore
ignore: [
'parts/**/*.js',
'**/_*.js'
]
}
)
.map(function (key) {
return [key, path.resolve('src/js', key)];
});
// `{ 'app.js': 'PATH/TO/PROJECT/src/js/app.js' }` のようなオブジェクトを entriesObj とする
let entriesObj = Object.fromEntries(entries);
// 以下、 parts に関する処理
partsCount = 0;
// flag の中で true になっている個数をカウント
Object.keys(flag).forEach(function (index) {
if (flag[index]) {
partsCount++;
}
});
if (partsCount > 0) {
// flag の中で true になっている個数が少なくとも1つある場合は、 `parts.js` キーを entriesObj に追加
entriesObj[`parts.js`] = [];
// entriesObj の `parts.js` キー に配列で複数のファイル (parts1.js, parts2.js) を指定
Object.keys(flag).forEach(function (index) {
if (flag[index]) {
entriesObj[`parts.js`].push(path.resolve(partsPath, `${index}.js`));
}
});
}
return entriesObj;
};
const configs = {
mode: development,
entry: entry(),
output: {
filename: '[name]',
},
devtool: 'inline-source-map',
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [
'dist/js/**/*.js'
],
}),
],
optimization: {
minimizer: [
new webpackTerser({
extractComments: 'some',
terserOptions: {
compress: {
drop_console: false,
},
},
}),
],
},
};
module.exports = configs;
</code></pre>
<ul>
<li>エントリーポイントには <code>glob.sync</code> から始まる処理で指定
<ul>
<li><code>src/js</code>下 の <code>.js</code> ファイルを <code>{ 'app.js': 'PATH/TO/PROJECT/src/js/app.js' }</code> のようにキーはファイル名、値がファイルへのフルパス、となるようなオブジェクトを作っています
<ul>
<li><code>ignore</code> で <code>src/js/parts/</code>下 は最初は除外しています</li>
<li>本題からは逸れますが <code>_*.js</code> で <code>_</code> 始まりのファイルも <code>ignore</code> 指定しています</li>
</ul></li>
</ul></li>
<li>オブジェクト <code>flag</code> のキーと <code>src/js/parts/</code>下 のファイル名を一致させている、という条件下でフラグの <code>true</code> or <code>false</code> によりエントリーポイントを変化させています
<ul>
<li>今回の出力は <code>dist/js/parts.min.js</code> でひとまとめにする前提にしています。 <code>app.min.js</code> の中には混ぜません</li>
<li>そのため、エントリーポイントを <code>{ 'app.js': [ 'PATH/TO/PROJECT/src/js/app.js', 'PATH/TO/PROJECT/src/js/parts/parts1.js', ... ] }</code> とするのではなく、 <code>{ 'app.js': 'PATH/TO/PROJECT/src/js/app.js', 'parts.js': [ 'PATH/TO/PROJECT/src/js/parts1.js', 'PATH/TO/PROJECT/src/js/parts/parts2.js', ... ] }</code> となるように処理を加えました</li>
</ul></li>
</ul>
<h3 id="Gulpタスク (JavaScriptに関する部分)"><a href="#Gulp%E3%82%BF%E3%82%B9%E3%82%AF+%28JavaScript%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E9%83%A8%E5%88%86%29">Gulpタスク (JavaScriptに関する部分)</a></h3>
<pre><code class="javascript">const { dest } = require('gulp');
const plumber = require('gulp-plumber');
const notify = require('gulp-notify');
const rename = require('gulp-rename');
const webpackStream = require('webpack-stream');
const webpackConfig = require('webpack.config');
const jsBuild = () => {
return webpackStream(webpackConfig)
.pipe(plumber({
errorHandler: notify.onError({
message: 'Error: <%= error.message %>',
title: 'jsLibBuild'
})
}))
.pipe(rename((path) => {
path.basename += '.min'
path.extname = '.js'
}))
.pipe(dest('dist/js'));
};
module.exports = jsBuild;
</code></pre>
<p>これでひとまず意図した出力が得られました。</p>
<h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2>
<ul>
<li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/sansaisoba/items/921438a19cbf5a31ec53">webpackの基本だけどハマりやすいentryの設定と[name] - Qiita</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://speakerdeck.com/tomof/webpackgahe-gu-bi-yao-de-he-gu-fen-kariduraifalseka">webpackが何故必要で、 何故分かりづらいのか - Speaker Deck</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/kaoru-furusawa/items/fb3f6a3b5023013f3122">webpack + glob でentryファイルを複数指定する方法 - Qiita</a></li>
<li><a target="_blank" rel="nofollow noopener" href="https://webpack.js.org/concepts/entry-points/#multi-page-application">webpackのentryファイルを複数指定、globパッケージの使い方 - Qiita</a></li>
</ul>
arm-band