大体の JavaScript は Webpack でバンドルするのですが、一部対象外の JavaScript を用意したときに Webpack でバンドルしたライブラリを外部から参照できなかったのでメモ。
構成
ディレクトリ構造
今回は以下のような環境を想定。
PROJECT_ROOT/
├ dist/
│ ├ js/
│ │ └ external.js // Webpack でバンドルしない JavaScript
│ │
│ └ index.html
│
├ src/
│ └ js/
│ └ app.js // Webpack でバンドルする JavaScript (ここでは例として jQuery を import)
│
├ package.json
└ webpack.config.js // src/js/app.js を dist/js/app.js に出力
src/js/app.js
import $ from 'jquery';
$(() => {
$('#verse1').text('Watching unseen untouched');
});
jQuery を import して、内部で使用している簡単な jQuery を作成。
dist/js/external.js
$(() => {
$('#verse2').text('Empty exposed');
});
バンドルしないスクリプトも似たような構成。ただし、 <script>
タグ で jQuery を読み込むことを前提とした作りになっています。
dist/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Empty Exposed</title>
<meta name="description" content="expose-loader のテスト">
</head>
<body>
<p id="verse1"></p>
<p id="verse2"></p>
<script src="./js/app.js" defer></script>
<script src="./js/external.js" defer></script>
</body>
</html>
単純に dist/js/app.js
と dist/js/external.js
を読み込んで実行する前提の HTML です。
webpack.config.js
const webpackTerser = require('terser-webpack-plugin');
const path = require('path');
const glob = require('glob');
const entry = () => {
const entries = glob
.sync(
'**/*.js',
{
cwd: './src/js'
}
)
.map(function (key) {
return [key, path.resolve('./src/js', key)];
});
return Object.fromEntries(entries)
};
const configs = {
mode: 'development',
entry: entry(),
output: {
filename: '[name]',
path: path.join(path.join(__dirname, 'dist'), 'js')
},
optimization: {
minimizer: [
new webpackTerser({
extractComments: 'some',
terserOptions: {
compress: {
drop_console: false,
},
},
}),
],
},
devtool: 'inline-source-map'
};
module.exports = configs;
webpack.config.js
はこのような感じで。
検証
この状態で Webpack でバンドルすると、 dist/js/external.js
からは dist/js/app.js
にバンドルされた jQuery が参照できません。
そのため、以下のようなエラーが表示されてしまいます。
Uncaught ReferenceError: $ is not defined
対処
そこで、 expose-loader を加えた ( yarn add -D expose-loader
) 上で webpack.config.js
を以下のように書き換えます。
coconst webpackTerser = require('terser-webpack-plugin');
const path = require('path');
const glob = require('glob');
const entry = () => {
const entries = glob
.sync(
'**/*.js',
{
cwd: './src/js'
}
)
.map(function (key) {
return [key, path.resolve('./src/js', key)];
});
return Object.fromEntries(entries)
};
const configs = {
mode: 'development',
entry: entry(),
output: {
filename: '[name]',
path: path.join(path.join(__dirname, 'dist'), 'js')
},
module: { // ここから
rules: [
{
test: require.resolve("jquery"),
loader: "expose-loader",
options: {
exposes: ["$", "jQuery"],
}
}
]
}, // ここを追記
optimization: {
minimizer: [
new webpackTerser({
extractComments: 'some',
terserOptions: {
compress: {
drop_console: false,
},
},
}),
],
},
devtool: 'inline-source-map'
};
module.exports = configs;
これでもう一度ビルド。
今度はエラーがなく、出力処理が正常にできたことが確認できました。OKです。