123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- /*************************************************************
- *
- * Copyright (c) 2018 The MathJax Consortium
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /**
- * @fileoverview Creates configurations for webpacking of MathJax components
- *
- * @author dpvc@mathjax.org (Davide Cervone)
- */
- const fs = require('fs');
- const path = require('path');
- const webpack = require('webpack');
- const TerserPlugin = require('terser-webpack-plugin');
- /**************************************************************/
- /**
- * @param {string} string The string whose special characters are to be escaped
- * @return {string} The string with regex special characters escaped
- */
- function quoteRE(string) {
- return string.replace(/([\\.{}[\]()?*^$])/g, '\\$1')
- }
- /**
- * Creates the plugin needed for including jsdir in the output
- *
- * @param {string} js The location of the compiled js files
- * @param {string} dir The directory of the component being built
- * @return {any[]} The plugin array (empty or with the conversion plugin)
- */
- const PLUGINS = function (js, dir) {
- const mjdir = path.resolve(__dirname, '..', 'js');
- const jsdir = path.resolve(dir, js);
- //
- // Record the js directory for the pack command
- //
- return [new webpack.DefinePlugin({
- __JSDIR__: jsdir
- })];
- };
- /**
- * Creates the plugin needed for converting mathjax references to component/lib references
- *
- * @param {string} js The location of the compiled js files
- * @param {string[]} lib The component library directories to be linked against
- * @param {string} dir The directory of the component being built
- * @return {any[]} The plugin array (empty or with the conversion plugin)
- */
- const RESOLVE = function (js, libs, dir) {
- const mjdir = path.resolve(__dirname, '..', 'js');
- const jsdir = path.resolve(dir, js);
- const mjRE = new RegExp('^(?:' + quoteRE(jsdir) + '|' + quoteRE(mjdir) + ')' + quoteRE(path.sep));
- const root = path.dirname(mjdir);
- //
- // Add directory names to libraries
- //
- libs = libs.map(lib => path.join(lib.charAt(0) === '.' ? dir : root, lib) + path.sep);
- //
- // Function replace imported files by ones in the specified component lib directories.
- //
- const replaceLibs = (resource) => {
- //
- // The full file name to check.
- //
- const request = require.resolve(
- resource.request ?
- resource.request.charAt(0) === '.' ? path.resolve(resource.path, resource.request) : resource.request :
- resource.path
- );
- //
- // Only check files in the MathJax js directory.
- //
- if (!request.match(mjRE)) return;
- //
- // Loop through the libraries and see if the imported file is there.
- // If so, replace the request with the library version and return.
- //
- for (const lib of libs) {
- const file = request.replace(mjRE, lib);
- if (fs.existsSync(file)) {
- resource.path = file;
- resource.request = undefined;
- return;
- }
- }
- }
- //
- // A plugin that looks for files and modules to see if they need replacing with library versions.
- //
- class ResolveReplacementPlugin {
- apply(compiler) {
- compiler.hooks.file.tap(ResolveReplacementPlugin.name, replaceLibs);
- compiler.hooks.module.tap(ResolveReplacementPlugin.name, replaceLibs);
- }
- }
- return {plugins: [new ResolveReplacementPlugin()]};
- }
- /**
- * Add babel-loader to appropriate directories
- *
- * @param {string} dir The directory for the component being built
- * @return {any} The modules specification for the webpack configuration
- */
- const MODULE = function (dir) {
- //
- // Only need to transpile our directory and components directory
- //
- const dirRE = (dir.substr(0, __dirname.length) === __dirname ? quoteRE(__dirname) :
- '(?:' + quoteRE(__dirname) + '|' + quoteRE(dir) + ')');
- return {
- // NOTE: for babel transpilation
- rules: [{
- test: new RegExp(dirRE + quoteRE(path.sep) + '.*\\.js$'),
- exclude: new RegExp(quoteRE(path.join(path.dirname(__dirname), 'es5') + path.sep)),
- use: {
- loader: 'babel-loader',
- options: {
- presets: ['@babel/env']
- }
- }
- }]
- }
- };
- /**
- * Create a webpack configuration for a distribution file
- *
- * @param {string} name The name of the component to create
- * @param {string} js The path to the compiled .js files
- * @param {string[]} libs Array of paths to component lib directories to link against
- * @param {string} dir The directory of the component buing built
- * @param {string} dist The path to the directory where the component .js file will be placed
- * (defaults to es5 in the same directory as the js directory)
- */
- const PACKAGE = function (name, js, libs, dir, dist) {
- const distDir = dist ? path.resolve(dir, dist) :
- path.resolve(path.dirname(js), 'es5', path.dirname(name));
- name = path.basename(name);
- return {
- name: name,
- entry: path.join(dir, name + '.js'),
- output: {
- path: distDir,
- filename: name + (dist === '.' ? '.min.js' : '.js')
- },
- target: ['web', 'es5'], // needed for IE11 and old browsers
- plugins: PLUGINS(js, dir),
- resolve: RESOLVE(js, libs, dir),
- module: MODULE(dir),
- performance: {
- hints: false
- },
- optimization: {
- minimize: true,
- minimizer: [new TerserPlugin({
- extractComments: false,
- terserOptions: {
- output: {
- ascii_only: true
- }
- }
- })]
- },
- mode: 'production'
- };
- }
- module.exports = PACKAGE;
|