@ckeditor/ckeditor5-dev-utils
Version:
Utils for CKEditor 5 development tools packages.
161 lines (138 loc) • 4.93 kB
JavaScript
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md.
*/
'use strict';
const path = require( 'path' );
const fs = require( 'fs-extra' );
const { CKEditorTranslationsPlugin } = require( '@ckeditor/ckeditor5-dev-translations' );
const bundler = require( '../bundler' );
const loaders = require( '../loaders' );
/**
* Returns a webpack configuration that creates a bundle file for the specified package. Thanks to that, plugins exported
* by the package can be added to DLL builds.
*
* @param {Object} webpack
* @param {Function} webpack.BannerPlugin Plugin used to add text to the top of the file.
* @param {Function} webpack.DllReferencePlugin Plugin used to import DLLs with webpack.
* @param {Object} options
* @param {String} options.themePath An absolute path to the theme package.
* @param {String} options.packagePath An absolute path to the root directory of the package.
* @param {String} options.manifestPath An absolute path to the CKEditor 5 DLL manifest file.
* @param {String} [options.tsconfigPath] An absolute path to the TypeScript configuration file.
* @param {Boolean} [options.isDevelopmentMode=false] Whether to build a dev mode of the package.
* @returns {Object}
*/
module.exports = function getDllPluginWebpackConfig( webpack, options ) {
// Terser requires webpack. However, it's needed in runtime. To avoid the "Cannot find module 'webpack'" error,
// let's load the Terser dependency when `getDllPluginWebpackConfig()` is executed.
// See: https://github.com/ckeditor/ckeditor5/issues/13136.
const TerserPlugin = require( 'terser-webpack-plugin' );
const { name: packageName } = fs.readJsonSync( path.join( options.packagePath, 'package.json' ) );
const langDirExists = fs.existsSync( path.join( options.packagePath, 'lang' ) );
const indexJsExists = fs.existsSync( path.join( options.packagePath, 'src', 'index.js' ) );
const webpackConfig = {
mode: options.isDevelopmentMode ? 'development' : 'production',
performance: { hints: false },
// Use the `index.js` file to prepare the build to avoid potential issues if a source code differs from the published one.
entry: path.join( options.packagePath, 'src', indexJsExists ? 'index.js' : 'index.ts' ),
output: {
library: [ 'CKEditor5', getGlobalKeyForPackage( packageName ) ],
path: path.join( options.packagePath, 'build' ),
filename: getIndexFileName( packageName ),
libraryTarget: 'window'
},
optimization: {
minimize: false
},
plugins: [
new webpack.BannerPlugin( {
banner: bundler.getLicenseBanner(),
raw: true
} ),
new webpack.DllReferencePlugin( {
manifest: require( options.manifestPath ),
scope: 'ckeditor5/src',
name: 'CKEditor5.dll'
} )
],
resolve: {
extensions: [ '.ts', '.js', '.json' ],
extensionAlias: {
'.js': [ '.js', '.ts' ]
}
},
module: {
rules: [
loaders.getIconsLoader( { matchExtensionOnly: true } ),
loaders.getStylesLoader( {
themePath: options.themePath,
minify: true
} ),
loaders.getTypeScriptLoader( {
configFile: options.tsconfigPath || 'tsconfig.json'
} )
]
}
};
// Force loading JS files first if the `index.js` file exists.
if ( indexJsExists ) {
webpackConfig.resolve.extensions = moveArrayItem(
webpackConfig.resolve.extensions,
webpackConfig.resolve.extensions.indexOf( '.js' ),
0
);
}
if ( langDirExists ) {
webpackConfig.plugins.push( new CKEditorTranslationsPlugin( {
// UI language. Language codes follow the https://en.wikipedia.org/wiki/ISO_639-1 format.
language: 'en',
additionalLanguages: 'all',
sourceFilesPattern: /^src[/\\].+\.[jt]s$/,
skipPluralFormFunction: true
} ) );
}
if ( options.isDevelopmentMode ) {
webpackConfig.devtool = 'source-map';
} else {
webpackConfig.optimization.minimize = true;
webpackConfig.optimization.minimizer = [
new TerserPlugin( {
terserOptions: {
output: {
// Preserve CKEditor 5 license comments.
comments: /^!/
}
},
extractComments: false
} )
];
}
return webpackConfig;
};
/**
* Transforms the package name (`@ckeditor/ckeditor5-foo-bar`) to the name that will be used while
* exporting the library into the global scope.
*
* @param {String} packageName
* @returns {String}
*/
function getGlobalKeyForPackage( packageName ) {
return packageName
.replace( /^@ckeditor\/ckeditor5?-/, '' )
.replace( /-([a-z])/g, ( match, p1 ) => p1.toUpperCase() );
}
/**
* Extracts the main file name from the package name.
*
* @param packageName
* @returns {String}
*/
function getIndexFileName( packageName ) {
return packageName.replace( /^@ckeditor\/ckeditor5?-/, '' ) + '.js';
}
function moveArrayItem( source, indexFrom, indexTo ) {
const tmp = source.slice();
tmp.splice( indexTo, 0, ...tmp.splice( indexFrom, 1 ) );
return tmp;
}